make this special-case hscale/vscale details, so we can use it for
authorHavoc Pennington <hp@pobox.com>
Mon, 4 Jun 2001 02:31:12 +0000 (02:31 +0000)
committerHavoc Pennington <hp@src.gnome.org>
Mon, 4 Jun 2001 02:31:12 +0000 (02:31 +0000)
2001-06-03  Havoc Pennington  <hp@pobox.com>

* gtk/gtkstyle.c (gtk_default_draw_slider): make this special-case
hscale/vscale details, so we can use it for scrollbar as well.

* tests/testgtk.c (reformat_value): honor digits from GtkScale

* gtk/gtkenums.h (GtkTroughType): Remove this enum
(GtkScrollType): add START and END from GtkTroughType

* gtk/gtkstyle.c (gtk_default_draw_slider): was not properly using
its x/y arguments

* gtk/gtkrange.h, gtk/gtkrange.c, gtk/gtkscrollbar.h,
gtk/gtkscrollbar.c, gtk/gtkscale.h, gtk/gtkscale.c,
gtk/gtkhscrollbar.h, gtk/gtkhscrollbar.c, gtk/gtkvscrollbar.h,
gtk/gtkvscrollbar.c, gtk/gtkhscale.h, gtk/gtkhscale.c,
gtk/gtkvscale.h, gtk/gtkvscale.c: Rewrite GtkRange and subclasses.

Notable changes in the process:

- stepper_size style property is the height for vertical
  ranges, width for horizontal; the other dimension matches
  the trough size
- add ability to do NeXT-style steppers (and several other styles
  that don't make any sense)
- added min_slider_length, fixed_slider_length properties to
          GtkScrollbar
        - cleaned some private (or at least useless) functions out of
          gtkscale.h
        - moved bindings to GtkScale from subclasses, even arrow keys,
  since blind users don't know scale orientation.
        - change move_slider action signal to use new GtkScrollType,
  remove GtkTroughType argument
- digits rounds the values a range will input to the given
  number of decimals, but will not try to force adjustment
  values set by other controllers. That is, we no longer
  modify adjustment->value inside a value_changed handler.
- added getters for GtkScale setters
        - middle-click begins a slider drag

23 files changed:
ChangeLog
ChangeLog.pre-2-0
ChangeLog.pre-2-10
ChangeLog.pre-2-2
ChangeLog.pre-2-4
ChangeLog.pre-2-6
ChangeLog.pre-2-8
docs/Changes-2.0.txt
docs/reference/gtk/tmpl/gtkenums.sgml
docs/reference/gtk/tmpl/gtkrange.sgml
docs/reference/gtk/tmpl/gtkscale.sgml
gtk/gtkenums.h
gtk/gtkhscale.c
gtk/gtkhscrollbar.c
gtk/gtkrange.c
gtk/gtkrange.h
gtk/gtkscale.c
gtk/gtkscale.h
gtk/gtkscrollbar.c
gtk/gtkstyle.c
gtk/gtkvscale.c
gtk/gtkvscrollbar.c
tests/testgtk.c

index 610b344f18748fb8c0af827fcfb192623cbdc8db..ac70a1def24f1aa9e64b04f9fd3d95a22adf3b2f 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,44 @@
+2001-06-03  Havoc Pennington  <hp@pobox.com>
+
+       * gtk/gtkstyle.c (gtk_default_draw_slider): make this special-case
+       hscale/vscale details, so we can use it for scrollbar as well.
+
+       * tests/testgtk.c (reformat_value): honor digits from GtkScale
+
+       * gtk/gtkenums.h (GtkTroughType): Remove this enum
+       (GtkScrollType): add START and END from GtkTroughType
+
+       * gtk/gtkstyle.c (gtk_default_draw_slider): was not properly using
+       its x/y arguments
+
+       * gtk/gtkrange.h, gtk/gtkrange.c, gtk/gtkscrollbar.h,
+       gtk/gtkscrollbar.c, gtk/gtkscale.h, gtk/gtkscale.c,
+       gtk/gtkhscrollbar.h, gtk/gtkhscrollbar.c, gtk/gtkvscrollbar.h,
+       gtk/gtkvscrollbar.c, gtk/gtkhscale.h, gtk/gtkhscale.c,
+       gtk/gtkvscale.h, gtk/gtkvscale.c: Rewrite GtkRange and subclasses.
+
+       Notable changes in the process:
+        
+       - stepper_size style property is the height for vertical 
+         ranges, width for horizontal; the other dimension matches
+         the trough size
+       - add ability to do NeXT-style steppers (and several other styles
+         that don't make any sense)
+       - added min_slider_length, fixed_slider_length properties to
+          GtkScrollbar
+        - cleaned some private (or at least useless) functions out of
+          gtkscale.h   
+        - moved bindings to GtkScale from subclasses, even arrow keys,
+         since blind users don't know scale orientation.
+        - change move_slider action signal to use new GtkScrollType,
+         remove GtkTroughType argument
+       - digits rounds the values a range will input to the given 
+         number of decimals, but will not try to force adjustment 
+         values set by other controllers. That is, we no longer
+         modify adjustment->value inside a value_changed handler.
+       - added getters for GtkScale setters
+        - middle-click begins a slider drag
+       
 Fri Jun  1 18:54:47 2001  Jonathan Blandford  <jrb@redhat.com>
 
        * gtk/gtktreeview.c: (gtk_tree_view_focus): Initial stab at
index 610b344f18748fb8c0af827fcfb192623cbdc8db..ac70a1def24f1aa9e64b04f9fd3d95a22adf3b2f 100644 (file)
@@ -1,3 +1,44 @@
+2001-06-03  Havoc Pennington  <hp@pobox.com>
+
+       * gtk/gtkstyle.c (gtk_default_draw_slider): make this special-case
+       hscale/vscale details, so we can use it for scrollbar as well.
+
+       * tests/testgtk.c (reformat_value): honor digits from GtkScale
+
+       * gtk/gtkenums.h (GtkTroughType): Remove this enum
+       (GtkScrollType): add START and END from GtkTroughType
+
+       * gtk/gtkstyle.c (gtk_default_draw_slider): was not properly using
+       its x/y arguments
+
+       * gtk/gtkrange.h, gtk/gtkrange.c, gtk/gtkscrollbar.h,
+       gtk/gtkscrollbar.c, gtk/gtkscale.h, gtk/gtkscale.c,
+       gtk/gtkhscrollbar.h, gtk/gtkhscrollbar.c, gtk/gtkvscrollbar.h,
+       gtk/gtkvscrollbar.c, gtk/gtkhscale.h, gtk/gtkhscale.c,
+       gtk/gtkvscale.h, gtk/gtkvscale.c: Rewrite GtkRange and subclasses.
+
+       Notable changes in the process:
+        
+       - stepper_size style property is the height for vertical 
+         ranges, width for horizontal; the other dimension matches
+         the trough size
+       - add ability to do NeXT-style steppers (and several other styles
+         that don't make any sense)
+       - added min_slider_length, fixed_slider_length properties to
+          GtkScrollbar
+        - cleaned some private (or at least useless) functions out of
+          gtkscale.h   
+        - moved bindings to GtkScale from subclasses, even arrow keys,
+         since blind users don't know scale orientation.
+        - change move_slider action signal to use new GtkScrollType,
+         remove GtkTroughType argument
+       - digits rounds the values a range will input to the given 
+         number of decimals, but will not try to force adjustment 
+         values set by other controllers. That is, we no longer
+         modify adjustment->value inside a value_changed handler.
+       - added getters for GtkScale setters
+        - middle-click begins a slider drag
+       
 Fri Jun  1 18:54:47 2001  Jonathan Blandford  <jrb@redhat.com>
 
        * gtk/gtktreeview.c: (gtk_tree_view_focus): Initial stab at
index 610b344f18748fb8c0af827fcfb192623cbdc8db..ac70a1def24f1aa9e64b04f9fd3d95a22adf3b2f 100644 (file)
@@ -1,3 +1,44 @@
+2001-06-03  Havoc Pennington  <hp@pobox.com>
+
+       * gtk/gtkstyle.c (gtk_default_draw_slider): make this special-case
+       hscale/vscale details, so we can use it for scrollbar as well.
+
+       * tests/testgtk.c (reformat_value): honor digits from GtkScale
+
+       * gtk/gtkenums.h (GtkTroughType): Remove this enum
+       (GtkScrollType): add START and END from GtkTroughType
+
+       * gtk/gtkstyle.c (gtk_default_draw_slider): was not properly using
+       its x/y arguments
+
+       * gtk/gtkrange.h, gtk/gtkrange.c, gtk/gtkscrollbar.h,
+       gtk/gtkscrollbar.c, gtk/gtkscale.h, gtk/gtkscale.c,
+       gtk/gtkhscrollbar.h, gtk/gtkhscrollbar.c, gtk/gtkvscrollbar.h,
+       gtk/gtkvscrollbar.c, gtk/gtkhscale.h, gtk/gtkhscale.c,
+       gtk/gtkvscale.h, gtk/gtkvscale.c: Rewrite GtkRange and subclasses.
+
+       Notable changes in the process:
+        
+       - stepper_size style property is the height for vertical 
+         ranges, width for horizontal; the other dimension matches
+         the trough size
+       - add ability to do NeXT-style steppers (and several other styles
+         that don't make any sense)
+       - added min_slider_length, fixed_slider_length properties to
+          GtkScrollbar
+        - cleaned some private (or at least useless) functions out of
+          gtkscale.h   
+        - moved bindings to GtkScale from subclasses, even arrow keys,
+         since blind users don't know scale orientation.
+        - change move_slider action signal to use new GtkScrollType,
+         remove GtkTroughType argument
+       - digits rounds the values a range will input to the given 
+         number of decimals, but will not try to force adjustment 
+         values set by other controllers. That is, we no longer
+         modify adjustment->value inside a value_changed handler.
+       - added getters for GtkScale setters
+        - middle-click begins a slider drag
+       
 Fri Jun  1 18:54:47 2001  Jonathan Blandford  <jrb@redhat.com>
 
        * gtk/gtktreeview.c: (gtk_tree_view_focus): Initial stab at
index 610b344f18748fb8c0af827fcfb192623cbdc8db..ac70a1def24f1aa9e64b04f9fd3d95a22adf3b2f 100644 (file)
@@ -1,3 +1,44 @@
+2001-06-03  Havoc Pennington  <hp@pobox.com>
+
+       * gtk/gtkstyle.c (gtk_default_draw_slider): make this special-case
+       hscale/vscale details, so we can use it for scrollbar as well.
+
+       * tests/testgtk.c (reformat_value): honor digits from GtkScale
+
+       * gtk/gtkenums.h (GtkTroughType): Remove this enum
+       (GtkScrollType): add START and END from GtkTroughType
+
+       * gtk/gtkstyle.c (gtk_default_draw_slider): was not properly using
+       its x/y arguments
+
+       * gtk/gtkrange.h, gtk/gtkrange.c, gtk/gtkscrollbar.h,
+       gtk/gtkscrollbar.c, gtk/gtkscale.h, gtk/gtkscale.c,
+       gtk/gtkhscrollbar.h, gtk/gtkhscrollbar.c, gtk/gtkvscrollbar.h,
+       gtk/gtkvscrollbar.c, gtk/gtkhscale.h, gtk/gtkhscale.c,
+       gtk/gtkvscale.h, gtk/gtkvscale.c: Rewrite GtkRange and subclasses.
+
+       Notable changes in the process:
+        
+       - stepper_size style property is the height for vertical 
+         ranges, width for horizontal; the other dimension matches
+         the trough size
+       - add ability to do NeXT-style steppers (and several other styles
+         that don't make any sense)
+       - added min_slider_length, fixed_slider_length properties to
+          GtkScrollbar
+        - cleaned some private (or at least useless) functions out of
+          gtkscale.h   
+        - moved bindings to GtkScale from subclasses, even arrow keys,
+         since blind users don't know scale orientation.
+        - change move_slider action signal to use new GtkScrollType,
+         remove GtkTroughType argument
+       - digits rounds the values a range will input to the given 
+         number of decimals, but will not try to force adjustment 
+         values set by other controllers. That is, we no longer
+         modify adjustment->value inside a value_changed handler.
+       - added getters for GtkScale setters
+        - middle-click begins a slider drag
+       
 Fri Jun  1 18:54:47 2001  Jonathan Blandford  <jrb@redhat.com>
 
        * gtk/gtktreeview.c: (gtk_tree_view_focus): Initial stab at
index 610b344f18748fb8c0af827fcfb192623cbdc8db..ac70a1def24f1aa9e64b04f9fd3d95a22adf3b2f 100644 (file)
@@ -1,3 +1,44 @@
+2001-06-03  Havoc Pennington  <hp@pobox.com>
+
+       * gtk/gtkstyle.c (gtk_default_draw_slider): make this special-case
+       hscale/vscale details, so we can use it for scrollbar as well.
+
+       * tests/testgtk.c (reformat_value): honor digits from GtkScale
+
+       * gtk/gtkenums.h (GtkTroughType): Remove this enum
+       (GtkScrollType): add START and END from GtkTroughType
+
+       * gtk/gtkstyle.c (gtk_default_draw_slider): was not properly using
+       its x/y arguments
+
+       * gtk/gtkrange.h, gtk/gtkrange.c, gtk/gtkscrollbar.h,
+       gtk/gtkscrollbar.c, gtk/gtkscale.h, gtk/gtkscale.c,
+       gtk/gtkhscrollbar.h, gtk/gtkhscrollbar.c, gtk/gtkvscrollbar.h,
+       gtk/gtkvscrollbar.c, gtk/gtkhscale.h, gtk/gtkhscale.c,
+       gtk/gtkvscale.h, gtk/gtkvscale.c: Rewrite GtkRange and subclasses.
+
+       Notable changes in the process:
+        
+       - stepper_size style property is the height for vertical 
+         ranges, width for horizontal; the other dimension matches
+         the trough size
+       - add ability to do NeXT-style steppers (and several other styles
+         that don't make any sense)
+       - added min_slider_length, fixed_slider_length properties to
+          GtkScrollbar
+        - cleaned some private (or at least useless) functions out of
+          gtkscale.h   
+        - moved bindings to GtkScale from subclasses, even arrow keys,
+         since blind users don't know scale orientation.
+        - change move_slider action signal to use new GtkScrollType,
+         remove GtkTroughType argument
+       - digits rounds the values a range will input to the given 
+         number of decimals, but will not try to force adjustment 
+         values set by other controllers. That is, we no longer
+         modify adjustment->value inside a value_changed handler.
+       - added getters for GtkScale setters
+        - middle-click begins a slider drag
+       
 Fri Jun  1 18:54:47 2001  Jonathan Blandford  <jrb@redhat.com>
 
        * gtk/gtktreeview.c: (gtk_tree_view_focus): Initial stab at
index 610b344f18748fb8c0af827fcfb192623cbdc8db..ac70a1def24f1aa9e64b04f9fd3d95a22adf3b2f 100644 (file)
@@ -1,3 +1,44 @@
+2001-06-03  Havoc Pennington  <hp@pobox.com>
+
+       * gtk/gtkstyle.c (gtk_default_draw_slider): make this special-case
+       hscale/vscale details, so we can use it for scrollbar as well.
+
+       * tests/testgtk.c (reformat_value): honor digits from GtkScale
+
+       * gtk/gtkenums.h (GtkTroughType): Remove this enum
+       (GtkScrollType): add START and END from GtkTroughType
+
+       * gtk/gtkstyle.c (gtk_default_draw_slider): was not properly using
+       its x/y arguments
+
+       * gtk/gtkrange.h, gtk/gtkrange.c, gtk/gtkscrollbar.h,
+       gtk/gtkscrollbar.c, gtk/gtkscale.h, gtk/gtkscale.c,
+       gtk/gtkhscrollbar.h, gtk/gtkhscrollbar.c, gtk/gtkvscrollbar.h,
+       gtk/gtkvscrollbar.c, gtk/gtkhscale.h, gtk/gtkhscale.c,
+       gtk/gtkvscale.h, gtk/gtkvscale.c: Rewrite GtkRange and subclasses.
+
+       Notable changes in the process:
+        
+       - stepper_size style property is the height for vertical 
+         ranges, width for horizontal; the other dimension matches
+         the trough size
+       - add ability to do NeXT-style steppers (and several other styles
+         that don't make any sense)
+       - added min_slider_length, fixed_slider_length properties to
+          GtkScrollbar
+        - cleaned some private (or at least useless) functions out of
+          gtkscale.h   
+        - moved bindings to GtkScale from subclasses, even arrow keys,
+         since blind users don't know scale orientation.
+        - change move_slider action signal to use new GtkScrollType,
+         remove GtkTroughType argument
+       - digits rounds the values a range will input to the given 
+         number of decimals, but will not try to force adjustment 
+         values set by other controllers. That is, we no longer
+         modify adjustment->value inside a value_changed handler.
+       - added getters for GtkScale setters
+        - middle-click begins a slider drag
+       
 Fri Jun  1 18:54:47 2001  Jonathan Blandford  <jrb@redhat.com>
 
        * gtk/gtktreeview.c: (gtk_tree_view_focus): Initial stab at
index 610b344f18748fb8c0af827fcfb192623cbdc8db..ac70a1def24f1aa9e64b04f9fd3d95a22adf3b2f 100644 (file)
@@ -1,3 +1,44 @@
+2001-06-03  Havoc Pennington  <hp@pobox.com>
+
+       * gtk/gtkstyle.c (gtk_default_draw_slider): make this special-case
+       hscale/vscale details, so we can use it for scrollbar as well.
+
+       * tests/testgtk.c (reformat_value): honor digits from GtkScale
+
+       * gtk/gtkenums.h (GtkTroughType): Remove this enum
+       (GtkScrollType): add START and END from GtkTroughType
+
+       * gtk/gtkstyle.c (gtk_default_draw_slider): was not properly using
+       its x/y arguments
+
+       * gtk/gtkrange.h, gtk/gtkrange.c, gtk/gtkscrollbar.h,
+       gtk/gtkscrollbar.c, gtk/gtkscale.h, gtk/gtkscale.c,
+       gtk/gtkhscrollbar.h, gtk/gtkhscrollbar.c, gtk/gtkvscrollbar.h,
+       gtk/gtkvscrollbar.c, gtk/gtkhscale.h, gtk/gtkhscale.c,
+       gtk/gtkvscale.h, gtk/gtkvscale.c: Rewrite GtkRange and subclasses.
+
+       Notable changes in the process:
+        
+       - stepper_size style property is the height for vertical 
+         ranges, width for horizontal; the other dimension matches
+         the trough size
+       - add ability to do NeXT-style steppers (and several other styles
+         that don't make any sense)
+       - added min_slider_length, fixed_slider_length properties to
+          GtkScrollbar
+        - cleaned some private (or at least useless) functions out of
+          gtkscale.h   
+        - moved bindings to GtkScale from subclasses, even arrow keys,
+         since blind users don't know scale orientation.
+        - change move_slider action signal to use new GtkScrollType,
+         remove GtkTroughType argument
+       - digits rounds the values a range will input to the given 
+         number of decimals, but will not try to force adjustment 
+         values set by other controllers. That is, we no longer
+         modify adjustment->value inside a value_changed handler.
+       - added getters for GtkScale setters
+        - middle-click begins a slider drag
+       
 Fri Jun  1 18:54:47 2001  Jonathan Blandford  <jrb@redhat.com>
 
        * gtk/gtktreeview.c: (gtk_tree_view_focus): Initial stab at
index 460b0cbc2a617d7d4fed217f2f9417a9b562b6d4..a7afa14cf0eb0a7b8a738bbd40232cab9a7b5098 100644 (file)
@@ -322,3 +322,10 @@ Incompatible Changes from GTK+-1.2 to GTK+-2.0:
 
 * GdkColorContext is gone; you probably weren't using it anyway.
   Use GdkColormap and the gdk_rgb_* functions instead.
+
+* GtkRange/GtkScrollbar/GtkScale were rewritten; this means that most
+  theme engines won't draw them properly, and any custom subclasses of
+  these widgets will need a rewrite (though if you could figure out
+  how to subclass the old version of GtkRange, you have our
+  respect). Also, GtkTroughType is gone.
+
index 01b1162c81bd45b0a64faa0f5d95cdddc136136b..7fbd1e25d183493a76c1a129408fddb7f6e7f34f 100644 (file)
@@ -248,11 +248,11 @@ contains grayscale or red-green-blue data.
 </para>
 
 @GTK_SCROLL_NONE: 
+@GTK_SCROLL_JUMP: 
 @GTK_SCROLL_STEP_BACKWARD: 
 @GTK_SCROLL_STEP_FORWARD: 
 @GTK_SCROLL_PAGE_BACKWARD: 
 @GTK_SCROLL_PAGE_FORWARD: 
-@GTK_SCROLL_JUMP: 
 @GTK_SCROLL_STEP_UP: 
 @GTK_SCROLL_STEP_DOWN: 
 @GTK_SCROLL_PAGE_UP: 
@@ -261,6 +261,8 @@ contains grayscale or red-green-blue data.
 @GTK_SCROLL_STEP_RIGHT: 
 @GTK_SCROLL_PAGE_LEFT: 
 @GTK_SCROLL_PAGE_RIGHT: 
+@GTK_SCROLL_START: 
+@GTK_SCROLL_END: 
 
 <!-- ##### ENUM GtkSelectionMode ##### -->
 <para>
@@ -325,16 +327,6 @@ for the default toolbar style.
 @GTK_TOOLBAR_BOTH_HORIZ: Buttons display icons and text alongside each
 other, rather than vertically stacked
 
-<!-- ##### ENUM GtkTroughType ##### -->
-<para>
-
-</para>
-
-@GTK_TROUGH_NONE: 
-@GTK_TROUGH_START: 
-@GTK_TROUGH_END: 
-@GTK_TROUGH_JUMP: 
-
 <!-- ##### ENUM GtkUpdateType ##### -->
 <para>
 
index 349085ee4e922ed6b0589362072bb96b860f1de7..6966f7864e3fadb962c9be0b28395aedfcb28e62 100644 (file)
@@ -72,6 +72,7 @@ GtkRange
 
 @range: the object which received the signal.
 @arg1: 
+<!-- # Unused Parameters # -->
 @arg2: 
 
 <!-- ##### ARG GtkRange:update-policy ##### -->
index 3df95306735a7af7792d7000e9cdff9d38684ab3..3f765150b756ca31aa2acf6f2645ecda3bc363c2 100644 (file)
@@ -72,16 +72,6 @@ Sets the position in which the current value is displayed.
 @pos: the position in which the current value is displayed.
 
 
-<!-- ##### FUNCTION gtk_scale_get_value_width ##### -->
-<para>
-An internal function used to get the maximum width needed to display the value
-string.
-</para>
-
-@scale: a #GtkScale.
-@Returns: the maximum width needed to display the value string.
-
-
 <!-- ##### SIGNAL GtkScale::format-value ##### -->
 <para>
 
index 9f70e393cc1c7c36feb181f7e09eeb3b9036e1ea..88c204a145c8603b5b4b55c00910ed9f17f243c6 100644 (file)
@@ -286,11 +286,11 @@ typedef enum                      /*< flags >*/
 typedef enum
 {
   GTK_SCROLL_NONE,
+  GTK_SCROLL_JUMP,
   GTK_SCROLL_STEP_BACKWARD,
   GTK_SCROLL_STEP_FORWARD,
   GTK_SCROLL_PAGE_BACKWARD,
   GTK_SCROLL_PAGE_FORWARD,
-  GTK_SCROLL_JUMP,
   GTK_SCROLL_STEP_UP,
   GTK_SCROLL_STEP_DOWN,
   GTK_SCROLL_PAGE_UP,
@@ -298,7 +298,9 @@ typedef enum
   GTK_SCROLL_STEP_LEFT,
   GTK_SCROLL_STEP_RIGHT,
   GTK_SCROLL_PAGE_LEFT,
-  GTK_SCROLL_PAGE_RIGHT
+  GTK_SCROLL_PAGE_RIGHT,
+  GTK_SCROLL_START,
+  GTK_SCROLL_END
 } GtkScrollType;
 
 /* list selection modes */
@@ -353,15 +355,6 @@ typedef enum
   GTK_TOOLBAR_BOTH_HORIZ
 } GtkToolbarStyle;
 
-/* Trough types for GtkRange */
-typedef enum
-{
-  GTK_TROUGH_NONE,
-  GTK_TROUGH_START,
-  GTK_TROUGH_END,
-  GTK_TROUGH_JUMP
-} GtkTroughType;
-
 /* Data update types (for ranges) */
 typedef enum
 {
index a59efe8894a01eb6c21523a9b3652c694c0c8771..4b6e34a4ccb0f6c48e7ca2d28f6b6778f5b069c4 100644 (file)
@@ -1,5 +1,5 @@
 /* GTK - The GIMP Toolkit
- * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ * Copyright (C) 2001 Red Hat, Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
 #include <stdio.h>
 #include "gtkhscale.h"
 #include "gtksignal.h"
-#include "gdk/gdkkeysyms.h"
 #include "gtkintl.h"
-#include "gtkbindings.h"
 
-#define SCALE_CLASS(w)  GTK_SCALE_GET_CLASS (w)
-#define RANGE_CLASS(w)  GTK_RANGE_GET_CLASS (w)
-
-enum {
-  PROP_0
-};
+static gpointer parent_class;
 
 static void     gtk_hscale_class_init       (GtkHScaleClass *klass);
 static void     gtk_hscale_init             (GtkHScale      *hscale);
-static void     gtk_hscale_get_property     (GObject        *object,
-                                            guint           prop_id,
-                                            GValue          *value,
-                                            GParamSpec      *pspec);
-static void     gtk_hscale_set_property     (GObject         *object,
-                                            guint            prop_id,
-                                            const GValue    *value,
-                                            GParamSpec      *pspec);
-static void     gtk_hscale_realize          (GtkWidget      *widget);
-static void     gtk_hscale_size_request     (GtkWidget      *widget,
-                                            GtkRequisition *requisition);
-static void     gtk_hscale_size_allocate    (GtkWidget      *widget,
-                                            GtkAllocation  *allocation);
-static void     gtk_hscale_pos_trough       (GtkHScale      *hscale,
-                                            gint           *x,
-                                            gint           *y,
-                                            gint           *w,
-                                            gint           *h);
-static void     gtk_hscale_pos_background   (GtkHScale      *hscale,
-                                            gint           *x,
-                                            gint           *y,
-                                            gint           *w,
-                                            gint           *h);
-static void     gtk_hscale_draw_slider      (GtkRange       *range);
-static void     gtk_hscale_draw_value       (GtkScale       *scale);
-
-static void     gtk_hscale_clear_background (GtkRange       *range);
-
+static gboolean gtk_hscale_expose           (GtkWidget      *widget,
+                                             GdkEventExpose *event);
 
 GtkType
 gtk_hscale_get_type (void)
@@ -94,124 +61,33 @@ gtk_hscale_get_type (void)
   return hscale_type;
 }
 
-#define add_slider_binding(binding_set, keyval, mask, scroll, trough) \
-  gtk_binding_entry_add_signal (binding_set, keyval, mask,             \
-                                "move_slider", 2,                      \
-                                GTK_TYPE_SCROLL_TYPE, scroll,          \
-                                GTK_TYPE_TROUGH_TYPE, trough)
-
 static void
 gtk_hscale_class_init (GtkHScaleClass *class)
 {
   GObjectClass *gobject_class;
-  GtkObjectClass *object_class;
   GtkWidgetClass *widget_class;
   GtkRangeClass *range_class;
-  GtkScaleClass *scale_class;
-  GtkBindingSet *binding_set;
-  
-  gobject_class = (GObjectClass*) class;
-  object_class = (GtkObjectClass*) class;
-  widget_class = (GtkWidgetClass*) class;
-  range_class = (GtkRangeClass*) class;
-  scale_class = (GtkScaleClass*) class;
-
-  gobject_class->set_property = gtk_hscale_set_property;
-  gobject_class->get_property = gtk_hscale_get_property;   
-  widget_class->realize = gtk_hscale_realize;
-  widget_class->size_request = gtk_hscale_size_request;
-  widget_class->size_allocate = gtk_hscale_size_allocate;
-  
-  range_class->slider_update = _gtk_range_default_hslider_update;
-  range_class->trough_click = _gtk_range_default_htrough_click;
-  range_class->motion = _gtk_range_default_hmotion;
-  range_class->draw_slider = gtk_hscale_draw_slider;
-  range_class->clear_background = gtk_hscale_clear_background;
   
-  scale_class->draw_value = gtk_hscale_draw_value;
-
-  binding_set = gtk_binding_set_by_class (object_class);
-
-  add_slider_binding (binding_set, GDK_Left, 0,
-                      GTK_SCROLL_STEP_LEFT, GTK_TROUGH_NONE);
-
-  add_slider_binding (binding_set, GDK_Left, GDK_CONTROL_MASK,
-                      GTK_SCROLL_PAGE_LEFT, GTK_TROUGH_NONE);
-
-  add_slider_binding (binding_set, GDK_KP_Left, 0,
-                      GTK_SCROLL_STEP_LEFT, GTK_TROUGH_NONE);
-
-  add_slider_binding (binding_set, GDK_KP_Left, GDK_CONTROL_MASK,
-                      GTK_SCROLL_PAGE_LEFT, GTK_TROUGH_NONE);
-
-
-  add_slider_binding (binding_set, GDK_Right, 0,
-                      GTK_SCROLL_STEP_RIGHT, GTK_TROUGH_NONE);
-
-  add_slider_binding (binding_set, GDK_Right, GDK_CONTROL_MASK,
-                      GTK_SCROLL_PAGE_RIGHT, GTK_TROUGH_NONE);
-
-  add_slider_binding (binding_set, GDK_KP_Right, 0,
-                      GTK_SCROLL_STEP_RIGHT, GTK_TROUGH_NONE);
-
-  add_slider_binding (binding_set, GDK_KP_Right, GDK_CONTROL_MASK,
-                      GTK_SCROLL_PAGE_RIGHT, GTK_TROUGH_NONE);
-
-  add_slider_binding (binding_set, GDK_Home, 0,
-                      GTK_SCROLL_NONE, GTK_TROUGH_START);
-
-  add_slider_binding (binding_set, GDK_KP_Home, 0,
-                      GTK_SCROLL_NONE, GTK_TROUGH_START);
-
+  gobject_class = G_OBJECT_CLASS (class);
+  widget_class = GTK_WIDGET_CLASS (class);
+  range_class = GTK_RANGE_CLASS (class);
 
-  add_slider_binding (binding_set, GDK_End, 0,
-                      GTK_SCROLL_NONE, GTK_TROUGH_END);
+  parent_class = g_type_class_peek_parent (class);
 
-  add_slider_binding (binding_set, GDK_KP_End, 0,
-                      GTK_SCROLL_NONE, GTK_TROUGH_END);
-}
-
-static void 
-gtk_hscale_set_property (GObject        *object,
-                        guint           prop_id,
-                        const GValue   *value,
-                        GParamSpec     *pspec)
-{
-  GtkHScale *hscale;
-  
-  hscale = GTK_HSCALE (object);
-  
-  switch (prop_id)
-    {
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-    }
-}
-
-static void 
-gtk_hscale_get_property (GObject                    *object,
-                        guint                       prop_id,
-                        GValue                     *value,
-                        GParamSpec                 *pspec)
-{
-  GtkHScale *hscale;
-  
-  hscale = GTK_HSCALE (object);
+  range_class->slider_detail = "hscale";
   
-  switch (prop_id)
-    {
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-    }
+  widget_class->expose_event = gtk_hscale_expose;
 }
 
 static void
 gtk_hscale_init (GtkHScale *hscale)
 {
-  GTK_WIDGET_SET_FLAGS (hscale, GTK_NO_WINDOW);
+  GtkRange *range;
+
+  range = GTK_RANGE (hscale);
+
+  range->orientation = GTK_ORIENTATION_HORIZONTAL;
+  range->flippable = TRUE;
 }
 
 GtkWidget*
@@ -223,305 +99,32 @@ gtk_hscale_new (GtkAdjustment *adjustment)
                           "adjustment", adjustment,
                           NULL);
 
-  GTK_RANGE (hscale) -> flippable = 1;
-
   return hscale;
 }
 
-
-static void
-gtk_hscale_realize (GtkWidget *widget)
-{
-  GtkRange *range;
-  GdkWindowAttr attributes;
-  gint attributes_mask;
-  gint x, y, w, h;
-  gint slider_width, slider_length;
-  
-  g_return_if_fail (widget != NULL);
-  g_return_if_fail (GTK_IS_HSCALE (widget));
-  
-  GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
-  range = GTK_RANGE (widget);
-
-  _gtk_range_get_props (range, &slider_width, NULL, NULL, NULL);
-  gtk_widget_style_get (widget, "slider_length", &slider_length, NULL);
-  
-  widget->window = gtk_widget_get_parent_window (widget);
-  gdk_window_ref (widget->window);
-  
-  gtk_hscale_pos_trough (GTK_HSCALE (widget), &x, &y, &w, &h);
-
-  attributes.x = x;
-  attributes.y = y;
-  attributes.width = w;
-  attributes.height = h;
-  attributes.wclass = GDK_INPUT_OUTPUT;
-  attributes.window_type = GDK_WINDOW_CHILD;
-  
-  attributes.event_mask = gtk_widget_get_events (widget) | 
-    (GDK_EXPOSURE_MASK |
-     GDK_BUTTON_PRESS_MASK |
-     GDK_BUTTON_RELEASE_MASK |
-     GDK_ENTER_NOTIFY_MASK |
-     GDK_LEAVE_NOTIFY_MASK);
-  attributes.visual = gtk_widget_get_visual (widget);
-  attributes.colormap = gtk_widget_get_colormap (widget);
-  
-  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
-  
-  range->trough = gdk_window_new (widget->window, &attributes, attributes_mask);
-  
-  attributes.width = slider_length;
-  attributes.height = slider_width;
-  attributes.event_mask |= (GDK_BUTTON_MOTION_MASK |
-                            GDK_POINTER_MOTION_HINT_MASK);
-  
-  range->slider = gdk_window_new (range->trough, &attributes, attributes_mask);
-  
-  widget->style = gtk_style_attach (widget->style, widget->window);
-  
-  gdk_window_set_user_data (range->trough, widget);
-  gdk_window_set_user_data (range->slider, widget);
-  
-  gtk_style_set_background (widget->style, range->trough, GTK_STATE_ACTIVE);
-  gtk_style_set_background (widget->style, range->slider, GTK_STATE_NORMAL);
-  
-  _gtk_range_slider_update (GTK_RANGE (widget));
-  
-  gdk_window_show (range->slider);
-}
-
-static void 
-gtk_hscale_clear_background (GtkRange    *range)
-{
-  GtkWidget *widget;
-  gint x, y, width, height;
-  
-  g_return_if_fail (range != NULL);
-  
-  widget = GTK_WIDGET (range);
-  
-  gtk_hscale_pos_background (GTK_HSCALE (range), &x, &y, &width, &height);
-  
-  gtk_widget_queue_clear_area (GTK_WIDGET (range),
-                               x, y, width, height);
-}
-
-static void
-gtk_hscale_size_request (GtkWidget      *widget,
-                         GtkRequisition *requisition)
-{
-  GtkScale *scale = GTK_SCALE (widget);
-  gint slider_width, slider_length, trough_border;
-  
-  g_return_if_fail (widget != NULL);
-  g_return_if_fail (GTK_IS_HSCALE (widget));
-  g_return_if_fail (requisition != NULL);
-  
-  _gtk_range_get_props (GTK_RANGE (scale),
-                       &slider_width, &trough_border, NULL, NULL);
-  gtk_widget_style_get (widget, "slider_length", &slider_length, NULL);
-
-  requisition->width = (slider_length + trough_border) * 2;
-  requisition->height = (slider_width + trough_border * 2);
-  
-  if (scale->draw_value)
-    {
-      gint value_width, value_height;
-      gtk_scale_get_value_size (scale, &value_width, &value_height);
-      
-      if ((scale->value_pos == GTK_POS_LEFT) ||
-          (scale->value_pos == GTK_POS_RIGHT))
-        {
-          requisition->width += value_width + SCALE_CLASS (scale)->value_spacing;
-          if (requisition->height < value_height)
-            requisition->height = value_height;
-        }
-      else if ((scale->value_pos == GTK_POS_TOP) ||
-               (scale->value_pos == GTK_POS_BOTTOM))
-        {
-          if (requisition->width < value_width)
-            requisition->width = value_width;
-          requisition->height += value_height;
-        }
-    }
-}
-
-static void
-gtk_hscale_size_allocate (GtkWidget     *widget,
-                          GtkAllocation *allocation)
+static gboolean
+gtk_hscale_expose (GtkWidget      *widget,
+                   GdkEventExpose *event)
 {
   GtkRange *range;
+  GtkHScale *hscale;
   GtkScale *scale;
-  gint width, height;
-  gint x, y;
-  
-  g_return_if_fail (widget != NULL);
-  g_return_if_fail (GTK_IS_HSCALE (widget));
-  g_return_if_fail (allocation != NULL);
-  
-  widget->allocation = *allocation;
-  if (GTK_WIDGET_REALIZED (widget))
-    {
-      range = GTK_RANGE (widget);
-      scale = GTK_SCALE (widget);
-      
-      gtk_hscale_pos_trough (GTK_HSCALE (widget), &x, &y, &width, &height);
-      
-      gdk_window_move_resize (range->trough, 
-                              x, y, width, height);
-      _gtk_range_slider_update (GTK_RANGE (widget));
-    }
-}
-
-static void
-gtk_hscale_pos_trough (GtkHScale *hscale,
-                       gint      *x,
-                       gint      *y,
-                       gint      *w,
-                       gint      *h)
-{
-  GtkWidget *widget = GTK_WIDGET (hscale);
-  GtkScale *scale = GTK_SCALE (hscale);
-  gint slider_width;
-  gint trough_border;
-  
-  _gtk_range_get_props (GTK_RANGE (scale),
-                       &slider_width, &trough_border, NULL, NULL);
-  
-  *w = widget->allocation.width;
-  *h = (slider_width + trough_border * 2);
-  
-  if (scale->draw_value)
-    {
-      gint value_width, value_height;
-      gtk_scale_get_value_size (scale, &value_width, &value_height);
-      
-      *x = 0;
-      *y = 0;
-      
-      switch (scale->value_pos)
-        {
-        case GTK_POS_LEFT:
-          *x += value_width + SCALE_CLASS (scale)->value_spacing;
-          *y = (widget->allocation.height - *h) / 2;
-          *w -= *x;
-          break;
-        case GTK_POS_RIGHT:
-          *w -= value_width + SCALE_CLASS (scale)->value_spacing;
-          *y = (widget->allocation.height - *h) / 2;
-          break;
-        case GTK_POS_TOP:
-          *y = (value_height + (widget->allocation.height - widget->requisition.height) / 2);
-          break;
-        case GTK_POS_BOTTOM:
-          *y = (widget->allocation.height - widget->requisition.height) / 2;
-          break;
-        }
-    }
-  else
-    {
-      *x = 0;
-      *y = (widget->allocation.height - *h) / 2;
-    }
-  *x += 1;
-  *w -= 2;
-  
-  *x += widget->allocation.x;
-  *y += widget->allocation.y;
-}
-
-static void
-gtk_hscale_pos_background (GtkHScale *hscale,
-                           gint      *x,
-                           gint      *y,
-                           gint      *w,
-                           gint      *h)
-{
-  GtkWidget *widget;
-  GtkScale *scale;
-  
-  gint tx, ty, twidth, theight;
-  
-  g_return_if_fail (hscale != NULL);
-  g_return_if_fail (GTK_IS_HSCALE (hscale));
-  g_return_if_fail ((x != NULL) && (y != NULL) && (w != NULL) && (h != NULL));
-  
-  gtk_hscale_pos_trough (hscale, &tx, &ty, &twidth, &theight);
-  
-  widget = GTK_WIDGET (hscale);
-  scale = GTK_SCALE (hscale);
-  
-  *x = widget->allocation.x;
-  *y = widget->allocation.y;
-  *w = widget->allocation.width;
-  *h = widget->allocation.height;
-  
-  switch (scale->value_pos)
-    {
-    case GTK_POS_LEFT:
-      *w -= twidth;
-      break;
-    case GTK_POS_RIGHT:
-      *x += twidth;
-      *w -= twidth;
-      break;
-    case GTK_POS_TOP:
-      *h -= theight;
-      break;
-    case GTK_POS_BOTTOM:
-      *y += theight;
-      *h -= theight;
-      break;
-    }
-  *w = MAX (*w, 0);
-  *h = MAX (*h, 0);
-}
-
-static void
-gtk_hscale_draw_slider (GtkRange *range)
-{
-  GtkStateType state_type;
-  
-  g_return_if_fail (range != NULL);
-  g_return_if_fail (GTK_IS_HSCALE (range));
-  
-  if (range->slider)
-    {
-      if ((range->in_child == RANGE_CLASS (range)->slider) ||
-          (range->click_child == RANGE_CLASS (range)->slider))
-        state_type = GTK_STATE_PRELIGHT;
-      else
-        state_type = GTK_STATE_NORMAL;
-      
-      gtk_paint_slider (GTK_WIDGET (range)->style, range->slider, state_type, 
-                       GTK_SHADOW_OUT,
-                       NULL, GTK_WIDGET (range), "hscale",
-                       0, 0, -1, -1, 
-                       GTK_ORIENTATION_HORIZONTAL); 
-    }
-}
-
-static void
-gtk_hscale_draw_value (GtkScale *scale)
-{
-  GtkStateType state_type;
-  GtkWidget *widget;
-  gint width, height;
-  gint x, y;
   
-  g_return_if_fail (scale != NULL);
-  g_return_if_fail (GTK_IS_HSCALE (scale));
-  
-  widget = GTK_WIDGET (scale);
+  range = GTK_RANGE (widget);
+  scale = GTK_SCALE (widget);
+  hscale = GTK_HSCALE (widget);
   
   if (scale->draw_value)
     {
       PangoLayout *layout;
       PangoRectangle logical_rect;
       gchar *txt;
+      gint x, y;
+      GtkStateType state_type;
+      gint value_spacing;
 
+      gtk_widget_style_get (widget, "value_spacing", &value_spacing, NULL);
+      
       txt = _gtk_scale_format_value (scale,
                                      GTK_RANGE (scale)->adjustment->value);
       
@@ -529,44 +132,37 @@ gtk_hscale_draw_value (GtkScale *scale)
       g_free (txt);
       
       pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
-
+      
       switch (scale->value_pos)
         {
         case GTK_POS_LEFT:
-          gdk_window_get_position (GTK_RANGE (scale)->trough, &x, &y);
-          gdk_window_get_size (GTK_RANGE (scale)->trough, &width, &height);
-          
-          x -= SCALE_CLASS (scale)->value_spacing + logical_rect.width;
-          y += (height - logical_rect.height) / 2;
+          x = range->range_rect.x - value_spacing - logical_rect.width;
+          y = range->range_rect.y + (range->range_rect.height - logical_rect.height) / 2;
           break;
-        case GTK_POS_RIGHT:
-          gdk_window_get_position (GTK_RANGE (scale)->trough, &x, &y);
-          gdk_window_get_size (GTK_RANGE (scale)->trough, &width, &height);
           
-          x += width + SCALE_CLASS (scale)->value_spacing;
-          y += (height - logical_rect.height) / 2;
+        case GTK_POS_RIGHT:
+          x = range->range_rect.x + range->range_rect.width + value_spacing;
+          y = range->range_rect.y + (range->range_rect.height - logical_rect.height) / 2;
           break;
-        case GTK_POS_TOP:
-          gdk_window_get_position (GTK_RANGE (scale)->slider, &x, NULL);
-          gdk_window_get_position (GTK_RANGE (scale)->trough, NULL, &y);
-          gdk_window_get_size (GTK_RANGE (scale)->slider, &width, NULL);
-          gdk_window_get_size (GTK_RANGE (scale)->trough, NULL, &height);
           
-          x += widget->allocation.x + (width - logical_rect.width) / 2;
-         x = CLAMP (x, widget->allocation.x,
-                    widget->allocation.x + widget->allocation.width - logical_rect.width);
-          y -= logical_rect.height;
+        case GTK_POS_TOP:
+          x = range->slider_start +
+            (range->slider_end - range->slider_start - logical_rect.width) / 2;
+          x = CLAMP (x, 0, widget->allocation.width - logical_rect.width);
+          y = range->range_rect.y - logical_rect.height - value_spacing;
           break;
-        case GTK_POS_BOTTOM:
-          gdk_window_get_position (GTK_RANGE (scale)->slider, &x, NULL);
-          gdk_window_get_position (GTK_RANGE (scale)->trough, NULL, &y);
-          gdk_window_get_size (GTK_RANGE (scale)->slider, &width, NULL);
-          gdk_window_get_size (GTK_RANGE (scale)->trough, NULL, &height);
           
-          x += widget->allocation.x + (width - logical_rect.width) / 2;
-         x = CLAMP (x, widget->allocation.x,
-                    widget->allocation.x + widget->allocation.width - logical_rect.width);
-          y += height;
+        case GTK_POS_BOTTOM:
+          x = range->slider_start +
+            (range->slider_end - range->slider_start - logical_rect.width) / 2;
+          x = CLAMP (x, 0, widget->allocation.width - logical_rect.width);
+          y = range->range_rect.y + range->range_rect.height + value_spacing;
+          break;
+
+        default:
+          g_return_val_if_reached (FALSE);
+          x = 0;
+          y = 0;
           break;
         }
       
@@ -586,4 +182,6 @@ gtk_hscale_draw_value (GtkScale *scale)
 
       g_object_unref (G_OBJECT (layout));
     }
+
+  return (* GTK_WIDGET_CLASS (parent_class)->expose_event) (widget, event);
 }
index 9ec6f22c48585d2ec1bc53be4ec56b6b2b03d5dc..0894187dec19036adfb13facc28bf483b9f38522 100644 (file)
@@ -1,5 +1,6 @@
 /* GTK - The GIMP Toolkit
  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ * Copyright (C) 2001 Red Hat, Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
 #include "gdk/gdkkeysyms.h"
 #include "gtkintl.h"
 
-
-#define EPSILON 0.01
-
-#define RANGE_CLASS(w)  GTK_RANGE_GET_CLASS (w)
-
-enum {
-  PROP_0
-};
-
 static void     gtk_hscrollbar_class_init       (GtkHScrollbarClass *klass);
 static void     gtk_hscrollbar_init             (GtkHScrollbar      *hscrollbar);
-static void     gtk_hscrollbar_get_property     (GObject            *object,
-                                                guint               prop_id,
-                                                GValue             *value,
-                                                GParamSpec         *pspec);
-static void     gtk_hscrollbar_set_property     (GObject            *object,
-                                                guint               prop_id,
-                                                const GValue       *value,
-                                                GParamSpec         *pspec);
-static void     gtk_hscrollbar_realize          (GtkWidget          *widget);
-static void     gtk_hscrollbar_size_request     (GtkWidget          *widget,
-                                                GtkRequisition     *requisition);
-static void     gtk_hscrollbar_size_allocate    (GtkWidget          *widget,
-                                                GtkAllocation      *allocation);
-static void     gtk_hscrollbar_draw_step_forw   (GtkRange           *range);
-static void     gtk_hscrollbar_draw_step_back   (GtkRange           *range);
-static void     gtk_hscrollbar_slider_update    (GtkRange           *range);
-static void     gtk_hscrollbar_calc_slider_size (GtkHScrollbar      *hscrollbar);
 
 GtkType
 gtk_hscrollbar_get_type (void)
@@ -86,69 +61,17 @@ gtk_hscrollbar_get_type (void)
 static void
 gtk_hscrollbar_class_init (GtkHScrollbarClass *class)
 {
-  GObjectClass *gobject_class;
-  GtkObjectClass *object_class;
-  GtkWidgetClass *widget_class;
-  GtkRangeClass *range_class;
-  
-  gobject_class = (GObjectClass*) class;
-  object_class = (GtkObjectClass*) class;
-  widget_class = (GtkWidgetClass*) class;
-  range_class = (GtkRangeClass*) class;
-  
-  gobject_class->set_property = gtk_hscrollbar_set_property;
-  gobject_class->get_property = gtk_hscrollbar_get_property;
-
-  widget_class->realize = gtk_hscrollbar_realize;
-  widget_class->size_request = gtk_hscrollbar_size_request;
-  widget_class->size_allocate = gtk_hscrollbar_size_allocate;
-  
-  range_class->draw_step_forw = gtk_hscrollbar_draw_step_forw;
-  range_class->draw_step_back = gtk_hscrollbar_draw_step_back;
-  range_class->slider_update = gtk_hscrollbar_slider_update;
-  range_class->trough_click = _gtk_range_default_htrough_click;
-  range_class->motion = _gtk_range_default_hmotion;
-}
-
-static void 
-gtk_hscrollbar_set_property (GObject                    *object,
-                            guint                       prop_id,
-                            const GValue               *value,
-                            GParamSpec                 *pspec)
-{
-  GtkHScrollbar *hscrollbar;
-  
-  hscrollbar = GTK_HSCROLLBAR (object);
-  
-  switch (prop_id)
-    {
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-    }
-}
-
-static void 
-gtk_hscrollbar_get_property (GObject                    *object,
-                            guint                       prop_id,
-                            GValue                     *value,
-                            GParamSpec                 *pspec)
-{
-  GtkHScrollbar *hscrollbar;
-  
-  hscrollbar = GTK_HSCROLLBAR (object);
-  
-  switch (prop_id)
-    {
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-    }
+  GTK_RANGE_CLASS (class)->stepper_detail = "hscrollbar";
 }
 
 static void
 gtk_hscrollbar_init (GtkHScrollbar *hscrollbar)
 {
+  GtkRange *range;
+
+  range = GTK_RANGE (hscrollbar);
+
+  range->orientation = GTK_ORIENTATION_HORIZONTAL;
 }
 
 GtkWidget*
@@ -163,282 +86,3 @@ gtk_hscrollbar_new (GtkAdjustment *adjustment)
   return hscrollbar;
 }
 
-
-static void
-gtk_hscrollbar_realize (GtkWidget *widget)
-{
-  GtkRange *range;
-  GdkWindowAttr attributes;
-  gint attributes_mask;
-  gint slider_width;
-  gint trough_border;
-  gint stepper_size;
-  
-  g_return_if_fail (widget != NULL);
-  g_return_if_fail (GTK_IS_HSCROLLBAR (widget));
-  
-  GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
-  range = GTK_RANGE (widget);
-  
-  _gtk_range_get_props (range, &slider_width, &trough_border,
-                       &stepper_size, NULL);
-
-  attributes.x = widget->allocation.x;
-  attributes.y = widget->allocation.y + (widget->allocation.height - widget->requisition.height) / 2;
-  attributes.width = widget->allocation.width;
-  attributes.height = widget->requisition.height;
-  attributes.wclass = GDK_INPUT_OUTPUT;
-  attributes.window_type = GDK_WINDOW_CHILD;
-  attributes.visual = gtk_widget_get_visual (widget);
-  attributes.colormap = gtk_widget_get_colormap (widget);
-  attributes.event_mask = gtk_widget_get_events (widget);
-  attributes.event_mask |= (GDK_EXPOSURE_MASK |
-                            GDK_BUTTON_PRESS_MASK |
-                            GDK_BUTTON_RELEASE_MASK |
-                            GDK_ENTER_NOTIFY_MASK |
-                            GDK_LEAVE_NOTIFY_MASK);
-  
-  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
-  widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
-  
-  range->trough = widget->window;
-  gdk_window_ref (range->trough);
-  
-  attributes.x = trough_border;
-  attributes.y = trough_border;
-  attributes.width = stepper_size;
-  attributes.height = stepper_size;
-  
-  range->step_back = gdk_window_new (range->trough, &attributes, attributes_mask);
-  
-  attributes.x = (widget->allocation.width -
-                  trough_border -
-                  stepper_size);
-  
-  range->step_forw = gdk_window_new (range->trough, &attributes, attributes_mask);
-  
-  attributes.x = 0;
-  attributes.y = trough_border;
-  attributes.width = RANGE_CLASS (widget)->min_slider_size;
-  attributes.height = slider_width;
-  
-  attributes.event_mask |= (GDK_BUTTON_MOTION_MASK |
-                            GDK_POINTER_MOTION_HINT_MASK);
-  
-  range->slider = gdk_window_new (range->trough, &attributes, attributes_mask);
-  
-  gtk_hscrollbar_calc_slider_size (GTK_HSCROLLBAR (widget));
-  _gtk_range_slider_update (GTK_RANGE (widget));
-  
-  widget->style = gtk_style_attach (widget->style, widget->window);
-  
-  gdk_window_set_user_data (range->trough, widget);
-  gdk_window_set_user_data (range->slider, widget);
-  gdk_window_set_user_data (range->step_forw, widget);
-  gdk_window_set_user_data (range->step_back, widget);
-  
-  gtk_style_set_background (widget->style, range->trough, GTK_STATE_ACTIVE);
-  gtk_style_set_background (widget->style, range->slider, GTK_STATE_NORMAL);
-  gtk_style_set_background (widget->style, range->step_forw, GTK_STATE_ACTIVE);
-  gtk_style_set_background (widget->style, range->step_back, GTK_STATE_ACTIVE);
-  
-  gdk_window_show (range->slider);
-  gdk_window_show (range->step_forw);
-  gdk_window_show (range->step_back);
-}
-
-static void
-gtk_hscrollbar_size_request (GtkWidget      *widget,
-                            GtkRequisition *requisition)
-{
-  gint slider_width;
-  gint trough_border;
-  gint stepper_size;
-  gint stepper_spacing;
-  
-  GtkRange *range = GTK_RANGE (widget);
-
-  _gtk_range_get_props (range, &slider_width, &trough_border, 
-                       &stepper_size, &stepper_spacing);
-  
-  requisition->width = (RANGE_CLASS (widget)->min_slider_size +
-                       stepper_size +
-                       stepper_spacing +
-                       trough_border) * 2;
-  requisition->height = (slider_width +
-                        trough_border * 2);
-}
-
-static void
-gtk_hscrollbar_size_allocate (GtkWidget     *widget,
-                              GtkAllocation *allocation)
-{
-  GtkRange *range;
-  gint trough_border;
-  gint stepper_size;
-  
-  g_return_if_fail (widget != NULL);
-  g_return_if_fail (GTK_IS_HSCROLLBAR (widget));
-  g_return_if_fail (allocation != NULL);
-  
-  widget->allocation = *allocation;
-  if (GTK_WIDGET_REALIZED (widget))
-    {
-      range = GTK_RANGE (widget);
-      
-      _gtk_range_get_props (range, NULL, &trough_border, 
-                           &stepper_size, NULL);
-  
-      gdk_window_move_resize (range->trough,
-                              allocation->x,
-                              allocation->y + (allocation->height - widget->requisition.height) / 2,
-                              allocation->width, widget->requisition.height);
-      gdk_window_move_resize (range->step_back,
-                              trough_border,
-                              trough_border,
-                              stepper_size,
-                              widget->requisition.height - trough_border * 2);
-      gdk_window_move_resize (range->step_forw,
-                              allocation->width - trough_border -
-                              stepper_size,
-                              trough_border,
-                              stepper_size,
-                              widget->requisition.height - trough_border * 2);
-      
-      _gtk_range_slider_update (GTK_RANGE (widget));
-    }
-}
-
-static void
-gtk_hscrollbar_draw_step_forw (GtkRange *range)
-{
-  GtkStateType state_type;
-  GtkShadowType shadow_type;
-  
-  g_return_if_fail (range != NULL);
-  g_return_if_fail (GTK_IS_HSCROLLBAR (range));
-  
-  if (GTK_WIDGET_DRAWABLE (range))
-    {
-      if (range->in_child == RANGE_CLASS (range)->step_forw)
-        {
-          if (range->click_child == RANGE_CLASS (range)->step_forw)
-            state_type = GTK_STATE_ACTIVE;
-          else
-            state_type = GTK_STATE_PRELIGHT;
-        }
-      else
-        state_type = GTK_STATE_NORMAL;
-      
-      if (range->click_child == RANGE_CLASS (range)->step_forw)
-        shadow_type = GTK_SHADOW_IN;
-      else
-        shadow_type = GTK_SHADOW_OUT;
-      
-      gtk_paint_arrow (GTK_WIDGET (range)->style, range->step_forw,
-                       state_type, shadow_type, 
-                       NULL, GTK_WIDGET (range), "hscrollbar",
-                       GTK_ARROW_RIGHT,
-                       TRUE, 0, 0, -1, -1);
-    }
-}
-
-static void
-gtk_hscrollbar_draw_step_back (GtkRange *range)
-{
-  GtkStateType state_type;
-  GtkShadowType shadow_type;
-  
-  g_return_if_fail (range != NULL);
-  g_return_if_fail (GTK_IS_HSCROLLBAR (range));
-  
-  if (GTK_WIDGET_DRAWABLE (range))
-    {
-      if (range->in_child == RANGE_CLASS (range)->step_back)
-        {
-          if (range->click_child == RANGE_CLASS (range)->step_back)
-            state_type = GTK_STATE_ACTIVE;
-          else
-            state_type = GTK_STATE_PRELIGHT;
-        }
-      else
-        state_type = GTK_STATE_NORMAL;
-      
-      if (range->click_child == RANGE_CLASS (range)->step_back)
-        shadow_type = GTK_SHADOW_IN;
-      else
-        shadow_type = GTK_SHADOW_OUT;
-      
-      gtk_paint_arrow (GTK_WIDGET (range)->style, range->step_back,
-                       state_type, shadow_type, 
-                       NULL, GTK_WIDGET (range), "hscrollbar",
-                       GTK_ARROW_LEFT,
-                       TRUE, 0, 0, -1, -1);
-    }
-}
-
-static void
-gtk_hscrollbar_slider_update (GtkRange *range)
-{
-  g_return_if_fail (range != NULL);
-  g_return_if_fail (GTK_IS_HSCROLLBAR (range));
-  
-  gtk_hscrollbar_calc_slider_size (GTK_HSCROLLBAR (range));
-  _gtk_range_default_hslider_update (range);
-}
-
-static void
-gtk_hscrollbar_calc_slider_size (GtkHScrollbar *hscrollbar)
-{
-  GtkRange *range;
-  gint step_back_x;
-  gint step_back_width;
-  gint step_forw_x;
-  gint slider_width;
-  gint slider_height;
-  gint stepper_spacing;
-  gint left, right;
-  gint width;
-  
-  g_return_if_fail (hscrollbar != NULL);
-  g_return_if_fail (GTK_IS_HSCROLLBAR (hscrollbar));
-
-  if (GTK_WIDGET_REALIZED (hscrollbar))
-    {
-      range = GTK_RANGE (hscrollbar);
-
-      _gtk_range_get_props (range, NULL, NULL, NULL, &stepper_spacing);
-      
-      gdk_window_get_size (range->step_back, &step_back_width, NULL);
-      gdk_window_get_position (range->step_back, &step_back_x, NULL);
-      gdk_window_get_position (range->step_forw, &step_forw_x, NULL);
-      
-      left = (step_back_x +
-              step_back_width +
-              stepper_spacing);
-      right = step_forw_x - stepper_spacing;
-      width = right - left;
-      
-      if ((range->adjustment->page_size > 0) &&
-          (range->adjustment->lower != range->adjustment->upper))
-        {
-          if (range->adjustment->page_size >
-              (range->adjustment->upper - range->adjustment->lower))
-            range->adjustment->page_size = range->adjustment->upper - range->adjustment->lower;
-          
-          width = (width * range->adjustment->page_size /
-                   (range->adjustment->upper - range->adjustment->lower));
-          
-          if (width < RANGE_CLASS (hscrollbar)->min_slider_size)
-            width = RANGE_CLASS (hscrollbar)->min_slider_size;
-        }
-      
-      gdk_window_get_size (range->slider, &slider_width, &slider_height);
-      
-      if (slider_width != width)
-       {
-         gdk_window_resize (range->slider, width, slider_height);
-         gdk_window_invalidate_rect (range->slider, NULL, FALSE);
-       }
-    }
-}
index f73244133e980ec101f1793471ee1fe771a8758d..e813a143218543f19dde4edf77b414ebc7dc9476 100644 (file)
@@ -1,5 +1,6 @@
 /* GTK - The GIMP Toolkit
  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ * Copyright (C) 2001 Red Hat, Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
 #include "gtksignal.h"
 #include "gtkintl.h"
 
-#define SCROLL_TIMER_LENGTH  20
 #define SCROLL_INITIAL_DELAY 250  /* must hold button this long before ... */
 #define SCROLL_LATER_DELAY   100  /* ... it starts repeating at this rate  */
-#define SCROLL_DELAY_LENGTH  300
-
-#define RANGE_CLASS(w)  GTK_RANGE_GET_CLASS (w)
+#define UPDATE_DELAY         300  /* Delay for queued update */
 
 enum {
   PROP_0,
@@ -49,59 +47,116 @@ enum {
   LAST_SIGNAL
 };
 
-static void gtk_range_class_init               (GtkRangeClass    *klass);
-static void gtk_range_init                     (GtkRange         *range);
-static void gtk_range_set_property             (GObject          *object,
-                                               guint             prop_id,
-                                               const GValue     *value,
-                                               GParamSpec       *pspec);
-static void gtk_range_get_property             (GObject          *object,
-                                               guint             prop_id,
-                                               GValue           *value,
-                                               GParamSpec       *pspec);
-static void gtk_range_destroy                  (GtkObject        *object);
-static void gtk_range_unrealize                (GtkWidget        *widget);
-static gint gtk_range_expose                   (GtkWidget        *widget,
-                                               GdkEventExpose   *event);
-static gint gtk_range_button_press             (GtkWidget        *widget,
-                                               GdkEventButton   *event);
-static gint gtk_range_button_release           (GtkWidget        *widget,
-                                               GdkEventButton   *event);
-static gint gtk_range_motion_notify            (GtkWidget        *widget,
-                                               GdkEventMotion   *event);
-static gint gtk_range_enter_notify             (GtkWidget        *widget,
-                                               GdkEventCrossing *event);
-static gint gtk_range_leave_notify             (GtkWidget        *widget,
-                                               GdkEventCrossing *event);
-static gint gtk_range_scroll_event             (GtkWidget        *widget,
-                                               GdkEventScroll   *event);
-static void gtk_range_style_set                 (GtkWidget       *widget,
-                                                GtkStyle        *previous_style);
+typedef enum {
+  MOUSE_OUTSIDE,
+  MOUSE_STEPPER_A,
+  MOUSE_STEPPER_B,
+  MOUSE_STEPPER_C,
+  MOUSE_STEPPER_D,
+  MOUSE_TROUGH,
+  MOUSE_SLIDER,
+  MOUSE_WIDGET /* inside widget but not in any of the above GUI elements */
+} MouseLocation;
+
+struct _GtkRangeLayout
+{
+  /* These are in widget->window coordinates */
+  GdkRectangle stepper_a;
+  GdkRectangle stepper_b;
+  GdkRectangle stepper_c;
+  GdkRectangle stepper_d;
+  /* The trough rectangle is the area the thumb can slide in, not the
+   * entire range_rect
+   */
+  GdkRectangle trough;
+  GdkRectangle slider;
+
+  /* Layout-related state */
+  
+  MouseLocation mouse_location;
+  /* last mouse coords we got, or -1 if mouse is outside the range */
+  gint mouse_x;
+  gint mouse_y;
+  /* "grabbed" mouse location, OUTSIDE for no grab */
+  MouseLocation grab_location;
+  gint grab_button; /* 0 if none */
+};
+
+static void gtk_range_class_init     (GtkRangeClass    *klass);
+static void gtk_range_init           (GtkRange         *range);
+static void gtk_range_set_property   (GObject          *object,
+                                      guint             prop_id,
+                                      const GValue     *value,
+                                      GParamSpec       *pspec);
+static void gtk_range_get_property   (GObject          *object,
+                                      guint             prop_id,
+                                      GValue           *value,
+                                      GParamSpec       *pspec);
+static void gtk_range_destroy        (GtkObject        *object);
+static void gtk_range_finalize       (GObject          *object);
+static void gtk_range_size_request   (GtkWidget        *widget,
+                                      GtkRequisition   *requisition);
+static void gtk_range_size_allocate  (GtkWidget        *widget,
+                                      GtkAllocation    *allocation);
+static void gtk_range_realize        (GtkWidget        *widget);
+static void gtk_range_unrealize      (GtkWidget        *widget);
+static gint gtk_range_expose         (GtkWidget        *widget,
+                                      GdkEventExpose   *event);
+static gint gtk_range_button_press   (GtkWidget        *widget,
+                                      GdkEventButton   *event);
+static gint gtk_range_button_release (GtkWidget        *widget,
+                                      GdkEventButton   *event);
+static gint gtk_range_motion_notify  (GtkWidget        *widget,
+                                      GdkEventMotion   *event);
+static gint gtk_range_enter_notify   (GtkWidget        *widget,
+                                      GdkEventCrossing *event);
+static gint gtk_range_leave_notify   (GtkWidget        *widget,
+                                      GdkEventCrossing *event);
+static gint gtk_range_scroll_event   (GtkWidget        *widget,
+                                      GdkEventScroll   *event);
+static void gtk_range_style_set      (GtkWidget        *widget,
+                                      GtkStyle         *previous_style);
+
+
+/* Range methods */
 
 static void gtk_range_move_slider              (GtkRange         *range,
-                                                GtkScrollType     scroll,
-                                                GtkTroughType     trough);
-
-static void gtk_real_range_draw_trough         (GtkRange         *range);
-static void gtk_real_range_draw_slider         (GtkRange         *range);
-static gint gtk_real_range_timer               (GtkRange         *range);
-static gint gtk_range_scroll                   (GtkRange         *range,
-                                               gdouble           jump_perc);
-
-static void gtk_range_add_timer                (GtkRange         *range);
-static void gtk_range_remove_timer             (GtkRange         *range);
-
-static void gtk_range_adjustment_changed       (GtkAdjustment    *adjustment,
-                                               gpointer          data);
-static void gtk_range_adjustment_value_changed (GtkAdjustment    *adjustment,
-                                               gpointer          data);
-
-static void gtk_range_trough_hdims             (GtkRange         *range,
-                                               gint             *left,
-                                               gint             *right);
-static void gtk_range_trough_vdims             (GtkRange         *range,
-                                               gint             *top,
-                                               gint             *bottom);
+                                                GtkScrollType     scroll);
+
+/* Internals */
+static void          gtk_range_scroll                   (GtkRange      *range,
+                                                         GtkScrollType  scroll);
+static gboolean      gtk_range_update_mouse_location    (GtkRange      *range);
+static void          gtk_range_calc_layout              (GtkRange      *range);
+static void          gtk_range_get_props                (GtkRange      *range,
+                                                         gint          *slider_width,
+                                                         gint          *stepper_size,
+                                                         gint          *trough_border,
+                                                         gint          *stepper_spacing);
+static void          gtk_range_calc_request             (GtkRange      *range,
+                                                         gint           slider_width,
+                                                         gint           stepper_size,
+                                                         gint           trough_border,
+                                                         gint           stepper_spacing,
+                                                         GdkRectangle  *range_rect,
+                                                         GtkBorder     *border,
+                                                         gint          *n_steppers_p,
+                                                         gint          *slider_length_p);
+static void          gtk_range_adjustment_value_changed (GtkAdjustment *adjustment,
+                                                         gpointer       data);
+static void          gtk_range_adjustment_changed       (GtkAdjustment *adjustment,
+                                                         gpointer       data);
+static void          gtk_range_add_step_timer           (GtkRange      *range,
+                                                         GtkScrollType  step);
+static void          gtk_range_remove_step_timer        (GtkRange      *range);
+static void          gtk_range_reset_update_timer       (GtkRange      *range);
+static void          gtk_range_remove_update_timer      (GtkRange      *range);
+static GdkRectangle* get_area                           (GtkRange      *range,
+                                                         MouseLocation  location);
+static void          gtk_range_internal_set_value       (GtkRange      *range,
+                                                         gdouble        value);
+static void          gtk_range_update_value             (GtkRange      *range);
+
 
 static GtkWidgetClass *parent_class = NULL;
 static guint signals[LAST_SIGNAL];
@@ -143,13 +198,17 @@ gtk_range_class_init (GtkRangeClass *class)
   object_class = (GtkObjectClass*) class;
   widget_class = (GtkWidgetClass*) class;
 
-  parent_class = gtk_type_class (GTK_TYPE_WIDGET);
+  parent_class = g_type_class_peek_parent (class);
 
   gobject_class->set_property = gtk_range_set_property;
   gobject_class->get_property = gtk_range_get_property;
+  gobject_class->finalize = gtk_range_finalize;
   object_class->destroy = gtk_range_destroy;
 
-  widget_class->unrealize = gtk_range_unrealize;
+  widget_class->size_request = gtk_range_size_request;
+  widget_class->size_allocate = gtk_range_size_allocate;
+  widget_class->realize = gtk_range_realize;
+  widget_class->unrealize = gtk_range_unrealize;  
   widget_class->expose_event = gtk_range_expose;
   widget_class->button_press_event = gtk_range_button_press;
   widget_class->button_release_event = gtk_range_button_release;
@@ -158,35 +217,21 @@ gtk_range_class_init (GtkRangeClass *class)
   widget_class->enter_notify_event = gtk_range_enter_notify;
   widget_class->leave_notify_event = gtk_range_leave_notify;
   widget_class->style_set = gtk_range_style_set;
-  
-  class->min_slider_size = 7;
-  class->trough = 1;
-  class->slider = 2;
-  class->step_forw = 3;
-  class->step_back = 4;
 
   class->move_slider = gtk_range_move_slider;
-  
-  class->draw_background = NULL;
-  class->clear_background = NULL;
-  class->draw_trough = gtk_real_range_draw_trough;
-  class->draw_slider = gtk_real_range_draw_slider;
-  class->draw_step_forw = NULL;
-  class->draw_step_back = NULL;
-  class->trough_click = NULL;
-  class->motion = NULL;
-  class->timer = gtk_real_range_timer;
 
+  class->slider_detail = "slider";
+  class->stepper_detail = "stepper";
+  
   signals[MOVE_SLIDER] =
     g_signal_newc ("move_slider",
                    G_TYPE_FROM_CLASS (object_class),
                    G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                    G_STRUCT_OFFSET (GtkRangeClass, move_slider),
                    NULL, NULL,
-                   gtk_marshal_VOID__ENUM_ENUM,
-                   G_TYPE_NONE, 2,
-                   GTK_TYPE_SCROLL_TYPE,
-                   GTK_TYPE_TROUGH_TYPE);
+                   gtk_marshal_VOID__ENUM,
+                   G_TYPE_NONE, 1,
+                   GTK_TYPE_SCROLL_TYPE);
 
   
   g_object_class_install_property (gobject_class,
@@ -216,16 +261,16 @@ gtk_range_class_init (GtkRangeClass *class)
                                                             G_PARAM_READABLE));
   gtk_widget_class_install_style_property (widget_class,
                                           g_param_spec_int ("trough_border",
-                                                            _("Trough Border"),
-                                                            _("Width of border around range"),
-                                                            0,
-                                                            G_MAXINT,
-                                                            1,
-                                                            G_PARAM_READABLE));
+                                                             _("Trough Border"),
+                                                             _("Spacing between thumb/steppers and outer trough bevel"),
+                                                             0,
+                                                             G_MAXINT,
+                                                             1,
+                                                             G_PARAM_READABLE));
   gtk_widget_class_install_style_property (widget_class,
                                           g_param_spec_int ("stepper_size",
                                                             _("Stepper Size"),
-                                                            _("Size of step buttons at ends"),
+                                                            _("Length of step buttons at ends"),
                                                             0,
                                                             G_MAXINT,
                                                             14,
@@ -234,7 +279,7 @@ gtk_range_class_init (GtkRangeClass *class)
                                           g_param_spec_int ("stepper_spacing",
                                                             _("Stepper Spacing"),
                                                             _("Spacing between step buttons and thumb"),
-                                                            G_MININT,
+                                                             0,
                                                             G_MAXINT,
                                                             0,
                                                             G_PARAM_READABLE));
@@ -277,7 +322,7 @@ gtk_range_get_property (GObject      *object,
   switch (prop_id)
     {
     case PROP_UPDATE_POLICY:
-      g_value_set_enum (value, range->policy);
+      g_value_set_enum (value, range->update_policy);
       break;
     case PROP_ADJUSTMENT:
       g_value_set_object (value, G_OBJECT (range->adjustment));
@@ -291,27 +336,21 @@ gtk_range_get_property (GObject      *object,
 static void
 gtk_range_init (GtkRange *range)
 {
-  range->trough = NULL;
-  range->slider = NULL;
-  range->step_forw = NULL;
-  range->step_back = NULL;
-
-  range->x_click_point = 0;
-  range->y_click_point = 0;
-  range->button = 0;
-  range->digits = -1;
-  range->policy = GTK_UPDATE_CONTINUOUS;
-  range->scroll_type = GTK_SCROLL_NONE;
-  range->in_child = 0;
-  range->click_child = 0;
-  range->need_timer = FALSE;
-  range->timer = 0;
-  range->flippable = 0;
-  range->old_value = 0.0;
-  range->old_lower = 0.0;
-  range->old_upper = 0.0;
-  range->old_page_size = 0.0;
   range->adjustment = NULL;
+  range->update_policy = GTK_UPDATE_CONTINUOUS;
+  range->inverted = FALSE;
+  range->flippable = FALSE;
+  range->min_slider_size = 1;
+  range->has_stepper_a = FALSE;
+  range->has_stepper_b = FALSE;
+  range->has_stepper_c = FALSE;
+  range->has_stepper_d = FALSE;
+  range->need_recalc = TRUE;
+  range->round_digits = -1;
+  range->layout = g_new0 (GtkRangeLayout, 1);
+  range->layout->grab_location = MOUSE_OUTSIDE;
+  range->layout->grab_button = 0;
+  range->timer = NULL;  
 }
 
 GtkAdjustment*
@@ -333,9 +372,9 @@ gtk_range_set_update_policy (GtkRange      *range,
   g_return_if_fail (range != NULL);
   g_return_if_fail (GTK_IS_RANGE (range));
 
-  if (range->policy != policy)
+  if (range->update_policy != policy)
     {
-      range->policy = policy;
+      range->update_policy = policy;
       g_object_notify (G_OBJECT (range), "update_policy");
     }
 }
@@ -356,8 +395,12 @@ gtk_range_set_adjustment (GtkRange      *range,
     {
       if (range->adjustment)
        {
-         gtk_signal_disconnect_by_data (GTK_OBJECT (range->adjustment),
-                                        (gpointer) range);
+         gtk_signal_disconnect_by_func (GTK_OBJECT (range->adjustment),
+                                         G_CALLBACK (gtk_range_adjustment_changed),
+                                        range);
+          gtk_signal_disconnect_by_func (GTK_OBJECT (range->adjustment),
+                                         G_CALLBACK (gtk_range_adjustment_value_changed),
+                                        range);
          gtk_object_unref (GTK_OBJECT (range->adjustment));
        }
 
@@ -367,17 +410,12 @@ gtk_range_set_adjustment (GtkRange      *range,
       
       gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
                          (GtkSignalFunc) gtk_range_adjustment_changed,
-                         (gpointer) range);
+                         range);
       gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
                          (GtkSignalFunc) gtk_range_adjustment_value_changed,
-                         (gpointer) range);
+                         range);
       
-      range->old_value = adjustment->value;
-      range->old_lower = adjustment->lower;
-      range->old_upper = adjustment->upper;
-      range->old_page_size = adjustment->page_size;
-      
-      gtk_range_adjustment_changed (adjustment, (gpointer) range);
+      gtk_range_adjustment_changed (adjustment, range);
       g_object_notify (G_OBJECT (range), "adjustment");
     }
 }
@@ -405,707 +443,656 @@ gtk_range_get_inverted (GtkRange *range)
   return range->inverted;
 }
 
-void
-_gtk_range_draw_background (GtkRange *range)
-{
-  g_return_if_fail (range != NULL);
-  g_return_if_fail (GTK_IS_RANGE (range));
-
-  if (range->trough && RANGE_CLASS (range)->draw_background)
-    (* RANGE_CLASS (range)->draw_background) (range);
+static gboolean
+should_invert (GtkRange *range)
+{  
+  if (range->orientation == GTK_ORIENTATION_HORIZONTAL)
+    return
+      (range->inverted && !range->flippable) ||
+      (range->inverted && range->flippable && gtk_widget_get_direction (GTK_WIDGET (range)) == GTK_TEXT_DIR_LTR) ||
+      (!range->inverted && range->flippable && gtk_widget_get_direction (GTK_WIDGET (range)) == GTK_TEXT_DIR_RTL);
+  else
+    return range->inverted;
 }
 
-void
-_gtk_range_clear_background (GtkRange *range)
+static void
+gtk_range_finalize (GObject *object)
 {
-  g_return_if_fail (range != NULL);
-  g_return_if_fail (GTK_IS_RANGE (range));
+  GtkRange *range;
 
-  if (range->trough && RANGE_CLASS (range)->clear_background)
-    (* RANGE_CLASS (range)->clear_background) (range);
-}
+  g_return_if_fail (GTK_IS_RANGE (object));
 
-void
-_gtk_range_draw_trough (GtkRange *range)
-{
-  g_return_if_fail (range != NULL);
-  g_return_if_fail (GTK_IS_RANGE (range));
+  range = GTK_RANGE (object);
 
-  if (range->trough && RANGE_CLASS (range)->draw_trough)
-    (* RANGE_CLASS (range)->draw_trough) (range);
+  g_free (range->layout);
+
+  (* G_OBJECT_CLASS (parent_class)->finalize) (object);
 }
 
-void
-_gtk_range_draw_slider (GtkRange *range)
+static void
+gtk_range_destroy (GtkObject *object)
 {
-  g_return_if_fail (range != NULL);
-  g_return_if_fail (GTK_IS_RANGE (range));
+  GtkRange *range;
 
-  if (range->slider && RANGE_CLASS (range)->draw_slider)
-    (* RANGE_CLASS (range)->draw_slider) (range);
-}
+  g_return_if_fail (GTK_IS_RANGE (object));
 
-void
-_gtk_range_draw_step_forw (GtkRange *range)
-{
-  g_return_if_fail (range != NULL);
-  g_return_if_fail (GTK_IS_RANGE (range));
+  range = GTK_RANGE (object);
+
+  gtk_range_remove_step_timer (range);
+  gtk_range_remove_update_timer (range);
+  
+  if (range->adjustment)
+    {
+      if (range->adjustment)
+       gtk_signal_disconnect_by_data (GTK_OBJECT (range->adjustment),
+                                      (gpointer) range);
+      gtk_object_unref (GTK_OBJECT (range->adjustment));
+      range->adjustment = NULL;
+    }
 
-  if (range->step_forw && RANGE_CLASS (range)->draw_step_forw)
-    (* RANGE_CLASS (range)->draw_step_forw) (range);
+  (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
 }
 
-void
-_gtk_range_draw_step_back (GtkRange *range)
+static void
+gtk_range_size_request (GtkWidget      *widget,
+                        GtkRequisition *requisition)
 {
-  g_return_if_fail (range != NULL);
-  g_return_if_fail (GTK_IS_RANGE (range));
+  GtkRange *range;
+  gint slider_width, stepper_size, trough_border, stepper_spacing;
+  GdkRectangle range_rect;
+  GtkBorder border;
+  
+  range = GTK_RANGE (widget);
+  
+  gtk_range_get_props (range,
+                       &slider_width, &stepper_size, &trough_border, &stepper_spacing);
+
+  gtk_range_calc_request (range, 
+                          slider_width, stepper_size, trough_border, stepper_spacing,
+                          &range_rect, &border, NULL, NULL);
 
-  if (range->step_back && RANGE_CLASS (range)->draw_step_back)
-    (* RANGE_CLASS (range)->draw_step_back) (range);
+  requisition->width = range_rect.width + border.left + border.right;
+  requisition->height = range_rect.height + border.top + border.bottom;
 }
 
-void
-_gtk_range_slider_update (GtkRange *range)
+static void
+gtk_range_size_allocate (GtkWidget     *widget,
+                         GtkAllocation *allocation)
 {
-  g_return_if_fail (range != NULL);
-  g_return_if_fail (GTK_IS_RANGE (range));
+  GtkRange *range;
+
+  range = GTK_RANGE (widget);
+
+  range->need_recalc = TRUE;
+  gtk_range_calc_layout (range);
 
-  if (RANGE_CLASS (range)->slider_update)
-    (* RANGE_CLASS (range)->slider_update) (range);
+  (* GTK_WIDGET_CLASS (parent_class)->size_allocate) (widget, allocation);
 }
 
-gboolean
-_gtk_range_trough_click (GtkRange  *range,
-                         gint       x,
-                         gint       y,
-                         gdouble   *jump_perc)
+static void
+gtk_range_realize (GtkWidget *widget)
 {
-  g_return_val_if_fail (range != NULL, GTK_TROUGH_NONE);
-  g_return_val_if_fail (GTK_IS_RANGE (range), GTK_TROUGH_NONE);
+  GtkRange *range;
+  GdkWindowAttr attributes;
+  gint attributes_mask;  
 
-  if (RANGE_CLASS (range)->trough_click)
-    return (* RANGE_CLASS (range)->trough_click) (range, x, y, jump_perc);
+  range = GTK_RANGE (widget);
 
-  return GTK_TROUGH_NONE;
+  gtk_range_calc_layout (range);
+  
+  GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
+
+  attributes.window_type = GDK_WINDOW_CHILD;
+  attributes.x = widget->allocation.x;
+  attributes.y = widget->allocation.y;
+  attributes.width = widget->allocation.width;
+  attributes.height = widget->allocation.height;
+  attributes.wclass = GDK_INPUT_OUTPUT;
+  attributes.visual = gtk_widget_get_visual (widget);
+  attributes.colormap = gtk_widget_get_colormap (widget);
+  attributes.event_mask = gtk_widget_get_events (widget);
+  attributes.event_mask |= (GDK_EXPOSURE_MASK |
+                           GDK_BUTTON_PRESS_MASK |
+                           GDK_BUTTON_RELEASE_MASK |
+                           GDK_ENTER_NOTIFY_MASK |
+                           GDK_LEAVE_NOTIFY_MASK |
+                            GDK_POINTER_MOTION_MASK |
+                            GDK_POINTER_MOTION_HINT_MASK);
+
+  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
+
+  widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
+  gdk_window_set_user_data (widget->window, range);
+
+  widget->style = gtk_style_attach (widget->style, widget->window);
+  gtk_style_set_background (widget->style, widget->window, widget->state);
 }
 
-static GdkRegion *
-get_window_region (GdkWindow *window)
+static void
+gtk_range_unrealize (GtkWidget *widget)
 {
-  GdkRectangle rect;
+  GtkRange *range;
+
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_RANGE (widget));
 
-  gdk_window_get_position (window, &rect.x, &rect.y);
-  gdk_window_get_size (window, &rect.width, &rect.height);
+  range = GTK_RANGE (widget);
 
-  return gdk_region_rectangle (&rect);
+  gtk_range_remove_step_timer (range);
+  gtk_range_remove_update_timer (range);
+  
+  if (GTK_WIDGET_CLASS (parent_class)->unrealize)
+    (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
 }
 
 static void
-move_and_update_window (GdkWindow *window, gint x, gint y)
+draw_stepper (GtkRange     *range,
+              GdkRectangle *rect,
+              GtkArrowType  arrow_type,
+              gboolean      clicked,
+              gboolean      prelighted,
+              GdkRectangle *area)
 {
-  GdkRegion *old_region;
-  GdkRegion *new_region;
-  GdkWindow *parent = gdk_window_get_parent (window);
-
-  old_region = get_window_region (window);
-  gdk_window_move (window, x, y);
-  new_region = get_window_region (window);
-                  
-  gdk_region_subtract (old_region, new_region);
-  gdk_window_invalidate_region (parent, old_region, TRUE);
-  gdk_region_destroy (old_region);
-  gdk_region_destroy (new_region);
-  
-  gdk_window_process_updates (parent, TRUE);
-}
+  GtkStateType state_type;
+  GtkShadowType shadow_type;
+  GdkRectangle intersection;
 
-static gboolean
-should_invert (GtkRange *range,
-               gboolean  horizontal)
-{  
-  if (horizontal)
-    return
-      (range->inverted && !range->flippable) ||
-      (range->inverted && range->flippable && gtk_widget_get_direction (GTK_WIDGET (range)) == GTK_TEXT_DIR_LTR) ||
-      (!range->inverted && range->flippable && gtk_widget_get_direction (GTK_WIDGET (range)) == GTK_TEXT_DIR_RTL);
+  /* More to get the right clip region than for efficiency */
+  if (!gdk_rectangle_intersect (area, rect, &intersection))
+    return;
+  
+  if (!GTK_WIDGET_IS_SENSITIVE (range))
+    state_type = GTK_STATE_INSENSITIVE;
+  else if (clicked)
+    state_type = GTK_STATE_ACTIVE;
+  else if (prelighted)
+    state_type = GTK_STATE_PRELIGHT;
+  else 
+    state_type = GTK_STATE_NORMAL;
+  
+  if (clicked)
+    shadow_type = GTK_SHADOW_IN;
   else
-    return range->inverted;
+    shadow_type = GTK_SHADOW_OUT;
+  
+  gtk_paint_arrow (GTK_WIDGET (range)->style,
+                   GTK_WIDGET (range)->window,
+                   state_type, shadow_type, 
+                   &intersection, GTK_WIDGET (range),
+                   GTK_RANGE_GET_CLASS (range)->stepper_detail,
+                   arrow_type,
+                   TRUE, rect->x, rect->y, rect->width, rect->height);
 }
 
-void
-_gtk_range_default_hslider_update (GtkRange *range)
+static gint
+gtk_range_expose (GtkWidget      *widget,
+                 GdkEventExpose *event)
 {
-  gint left;
-  gint right;
-  gint x;
-  gint trough_border;
+  GtkRange *range;
+  gboolean sensitive;
+  GtkStateType state;
+  GdkRectangle area;
+  
+  g_return_val_if_fail (widget != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);
 
-  g_return_if_fail (range != NULL);
-  g_return_if_fail (GTK_IS_RANGE (range));
+  range = GTK_RANGE (widget);
 
-  _gtk_range_get_props (range, NULL, &trough_border, NULL, NULL);
+  gtk_range_calc_layout (range);
 
-  if (GTK_WIDGET_REALIZED (range))
+  sensitive = GTK_WIDGET_IS_SENSITIVE (widget);
+  
+  /* Just to be confusing, we draw the trough for the whole
+   * range rectangle, not the trough rectangle (the trough
+   * rectangle is just for hit detection)
+   */
+  /* The gdk_rectangle_intersect is more to get the right
+   * clip region (limited to range_rect) than for efficiency
+   */
+  if (gdk_rectangle_intersect (&event->area, &range->range_rect,
+                               &area))
     {
-      gtk_range_trough_hdims (range, &left, &right);
-      x = left;
-
-      if (range->adjustment->value < range->adjustment->lower)
-       {
-         range->adjustment->value = range->adjustment->lower;
-         gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
-       }
-      else if (range->adjustment->value > range->adjustment->upper)
-       {
-         range->adjustment->value = range->adjustment->upper;
-         gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
-       }
-
-      if (range->adjustment->lower != (range->adjustment->upper - range->adjustment->page_size))
-       x += ((right - left) * (range->adjustment->value - range->adjustment->lower) /
-             (range->adjustment->upper - range->adjustment->lower - range->adjustment->page_size));
-
-      if (x < left)
-       x = left;
-      else if (x > right)
-       x = right;
-
-      if (should_invert (range, TRUE))
-       x = right - (x - left);
+      gtk_paint_box (widget->style,
+                     widget->window,
+                     sensitive ? GTK_STATE_ACTIVE : GTK_STATE_INSENSITIVE,
+                     GTK_SHADOW_IN,
+                     &area, GTK_WIDGET(range), "trough",
+                     range->range_rect.x,
+                     range->range_rect.y,
+                     range->range_rect.width,
+                     range->range_rect.height);
       
-      move_and_update_window (range->slider, x, trough_border);
+                 
+      if (sensitive &&
+          GTK_WIDGET_HAS_FOCUS (range))
+        gtk_paint_focus (widget->style,
+                         widget->window,
+                         &area, widget, "trough",
+                         range->range_rect.x,
+                         range->range_rect.y,
+                         range->range_rect.width,
+                         range->range_rect.height);
     }
-}
 
-void
-_gtk_range_default_vslider_update (GtkRange *range)
-{
-  gint top;
-  gint bottom;
-  gint y;
-  gint trough_border;
-
-  g_return_if_fail (range != NULL);
-  g_return_if_fail (GTK_IS_RANGE (range));
-
-  _gtk_range_get_props (range, NULL, &trough_border, NULL, NULL);
+  if (!sensitive)
+    state = GTK_STATE_INSENSITIVE;
+  else if (range->layout->mouse_location == MOUSE_SLIDER)
+    state = GTK_STATE_PRELIGHT;
+  else
+    state = GTK_STATE_NORMAL;
 
-  if (GTK_WIDGET_REALIZED (range))
+  if (gdk_rectangle_intersect (&event->area,
+                               &range->layout->slider,
+                               &area))
     {
-      gtk_range_trough_vdims (range, &top, &bottom);
-      y = top;
-
-      if (range->adjustment->value < range->adjustment->lower)
-       {
-         range->adjustment->value = range->adjustment->lower;
-         gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
-       }
-      else if (range->adjustment->value > range->adjustment->upper)
-       {
-         range->adjustment->value = range->adjustment->upper;
-         gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
-       }
-
-      if (range->adjustment->lower != (range->adjustment->upper - range->adjustment->page_size))
-       y += ((bottom - top) * (range->adjustment->value - range->adjustment->lower) /
-             (range->adjustment->upper - range->adjustment->lower - range->adjustment->page_size));
+      gtk_paint_slider (widget->style,
+                        widget->window,
+                        state,
+                        GTK_SHADOW_OUT,
+                        &event->area,
+                        widget,
+                        GTK_RANGE_GET_CLASS (range)->slider_detail,
+                        range->layout->slider.x,
+                        range->layout->slider.y,
+                        range->layout->slider.width,
+                        range->layout->slider.height,
+                        range->orientation);
+    }
+  
+  if (range->has_stepper_a)
+    draw_stepper (range, &range->layout->stepper_a,
+                  range->orientation == GTK_ORIENTATION_VERTICAL ? GTK_ARROW_UP : GTK_ARROW_LEFT,
+                  range->layout->grab_location == MOUSE_STEPPER_A,
+                  range->layout->mouse_location == MOUSE_STEPPER_A,
+                  &event->area);
+
+  if (range->has_stepper_b)
+    draw_stepper (range, &range->layout->stepper_b,
+                  range->orientation == GTK_ORIENTATION_VERTICAL ? GTK_ARROW_DOWN : GTK_ARROW_RIGHT,
+                  range->layout->grab_location == MOUSE_STEPPER_B,
+                  range->layout->mouse_location == MOUSE_STEPPER_B,
+                  &event->area);
+
+  if (range->has_stepper_c)
+    draw_stepper (range, &range->layout->stepper_c,
+                  range->orientation == GTK_ORIENTATION_VERTICAL ? GTK_ARROW_UP : GTK_ARROW_LEFT,
+                  range->layout->grab_location == MOUSE_STEPPER_C,
+                  range->layout->mouse_location == MOUSE_STEPPER_C,
+                  &event->area);
+
+  if (range->has_stepper_d)
+    draw_stepper (range, &range->layout->stepper_d,
+                  range->orientation == GTK_ORIENTATION_VERTICAL ? GTK_ARROW_DOWN : GTK_ARROW_RIGHT,
+                  range->layout->grab_location == MOUSE_STEPPER_D,
+                  range->layout->mouse_location == MOUSE_STEPPER_D,
+                  &event->area);
+  
+  return FALSE;
+}
 
-      if (y < top)
-       y = top;
-      else if (y > bottom)
-       y = bottom;
+static void
+range_grab_add (GtkRange      *range,
+                MouseLocation  location,
+                gint           button)
+{
+  /* we don't actually gtk_grab, since a button is down */
 
-      if (should_invert (range, FALSE))
-       y = bottom - (y - top);
-      
-      move_and_update_window (range->slider, trough_border, y);
-    }
+  range->layout->grab_location = location;
+  range->layout->grab_button = button;
+  
+  if (gtk_range_update_mouse_location (range))
+    gtk_widget_queue_draw (GTK_WIDGET (range));
 }
 
-gboolean
-_gtk_range_default_htrough_click (GtkRange  *range,
-                                  gint       x,
-                                  gint       y,
-                                  gdouble   *jump_perc)
+static void
+range_grab_remove (GtkRange *range)
 {
-  gint trough_border;
-  gint trough_width;
-  gint trough_height;
-  gint slider_x;
-  gint slider_length;
-  gint left, right;
+  range->layout->grab_location = MOUSE_OUTSIDE;
+  range->layout->grab_button = 0;
 
-  g_return_val_if_fail (range != NULL, GTK_TROUGH_NONE);
-  g_return_val_if_fail (GTK_IS_RANGE (range), GTK_TROUGH_NONE);
+  if (gtk_range_update_mouse_location (range))
+    gtk_widget_queue_draw (GTK_WIDGET (range));
+}
 
-  _gtk_range_get_props (range, NULL, &trough_border, NULL, NULL);
+static GtkScrollType
+range_get_scroll_for_grab (GtkRange      *range)
+{  
+  switch (range->layout->grab_location)
+    {
+      /* Backward stepper */
+    case MOUSE_STEPPER_A:
+    case MOUSE_STEPPER_C:
+      switch (range->layout->grab_button)
+        {
+        case 1:
+          return GTK_SCROLL_STEP_BACKWARD;
+          break;
+        case 2:
+          return GTK_SCROLL_PAGE_BACKWARD;
+          break;
+        case 3:
+          return GTK_SCROLL_START;
+          break;
+        }
+      break;
 
-  gtk_range_trough_hdims (range, &left, &right);
-  gdk_window_get_size (range->slider, &slider_length, NULL);
-  right += slider_length;
+      /* Forward stepper */
+    case MOUSE_STEPPER_B:
+    case MOUSE_STEPPER_D:
+      switch (range->layout->grab_button)
+        {
+        case 1:
+          return GTK_SCROLL_STEP_FORWARD;
+          break;
+        case 2:
+          return GTK_SCROLL_PAGE_FORWARD;
+          break;
+        case 3:
+          return GTK_SCROLL_END;
+          break;
+        }
+      break;
 
-  if (should_invert (range, TRUE))
-    x = (right - x) + left;
+      /* In the trough */
+    case MOUSE_TROUGH:
+      {
+        if (range->trough_click_forward)
+          {
+            return range->layout->grab_button == 3
+              ? GTK_SCROLL_PAGE_FORWARD : GTK_SCROLL_STEP_FORWARD;
+          }
+        else
+          {
+            return range->layout->grab_button == 3
+              ? GTK_SCROLL_PAGE_BACKWARD : GTK_SCROLL_STEP_BACKWARD;
+          }
+      }
+      break;
 
-  if ((x > left) && (y > trough_border))
-    {
-      gdk_window_get_size (range->trough, &trough_width, &trough_height);
-      
-      if ((x < right) && (y < (trough_height - trough_border)))
-       {
-         if (jump_perc)
-           {
-             *jump_perc = ((gdouble) (x - left)) / ((gdouble) (right - left));
-             return GTK_TROUGH_JUMP;
-           }
-         
-         gdk_window_get_position (range->slider, &slider_x, NULL);
-         
-         if (x < slider_x)
-           return GTK_TROUGH_START;
-         else
-           return GTK_TROUGH_END;
-       }
+    case MOUSE_OUTSIDE:
+    case MOUSE_SLIDER:
+    case MOUSE_WIDGET:
+      break;
     }
 
-  return GTK_TROUGH_NONE;
+  return GTK_SCROLL_NONE;
 }
 
-gboolean
-_gtk_range_default_vtrough_click (GtkRange  *range,
-                                  gint       x,
-                                  gint       y,
-                                  gdouble   *jump_perc)
+static gdouble
+coord_to_value (GtkRange *range,
+                gint      coord)
 {
-  gint trough_border;
-  gint trough_width;
-  gint trough_height;
-  gint slider_y;
-  gint top, bottom;
-  gint slider_length;
-
-  g_return_val_if_fail (range != NULL, GTK_TROUGH_NONE);
-  g_return_val_if_fail (GTK_IS_RANGE (range), GTK_TROUGH_NONE);
-
-  _gtk_range_get_props (range, NULL, &trough_border, NULL, NULL);
+  gdouble frac;
+  gdouble value;
   
-  gtk_range_trough_vdims (range, &top, &bottom);
-  gdk_window_get_size (range->slider, NULL, &slider_length);
-  bottom += slider_length;
+  if (range->orientation == GTK_ORIENTATION_VERTICAL)
+    frac = ((coord - range->layout->trough.y) /
+            (gdouble) (range->layout->trough.height - range->layout->slider.height));
+  else
+    frac = ((coord - range->layout->trough.x) /
+            (gdouble) (range->layout->trough.width - range->layout->slider.width));
 
-  if (should_invert (range, FALSE))
-    y = (bottom - y) + top;
+  if (should_invert (range))
+    frac = 1.0 - frac;
   
-  if ((x > trough_border) && (y > top))
-    {
-      gdk_window_get_size (range->trough, &trough_width, &trough_height);
-
-      if ((x < (trough_width - trough_border) && (y < bottom)))
-       {
-         if (jump_perc)
-           {
-             *jump_perc = ((gdouble) (y - top)) / ((gdouble) (bottom - top));
-
-             return GTK_TROUGH_JUMP;
-           }
-         
-         gdk_window_get_position (range->slider, NULL, &slider_y);
-         
-         if (y < slider_y)
-           return GTK_TROUGH_START;
-         else
-           return GTK_TROUGH_END;
-       }
-    }
+  value = range->adjustment->lower +
+    frac * (range->adjustment->upper - range->adjustment->lower - range->adjustment->page_size);
 
-  return GTK_TROUGH_NONE;
+  return value;
 }
 
-void
-_gtk_range_default_hmotion (GtkRange *range,
-                            gint      xdelta,
-                            gint      ydelta)
+static gint
+gtk_range_button_press (GtkWidget      *widget,
+                       GdkEventButton *event)
 {
-  gdouble old_value;
-  gint left, right;
-  gint slider_x, slider_y;
-  gint new_pos;
-
-  g_return_if_fail (GTK_IS_RANGE (range));
-  g_return_if_fail (GTK_WIDGET_REALIZED (range));
-
-  gdk_window_get_position (range->slider, &slider_x, &slider_y);
-  gtk_range_trough_hdims (range, &left, &right);
-
-  if (left == right)
-    return;
-
-  new_pos = slider_x + xdelta;
-
-  if (should_invert (range, TRUE))
-    new_pos = (right - new_pos) + left;
+  GtkRange *range;
 
-  if (new_pos < left)
-    new_pos = left;
-  else if (new_pos > right)
-    new_pos = right;
+  g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);
 
-  old_value = range->adjustment->value;
-  range->adjustment->value = ((range->adjustment->upper -
-                              range->adjustment->lower -
-                              range->adjustment->page_size) *
-                             (new_pos - left) / (right - left) +
-                             range->adjustment->lower);
+  range = GTK_RANGE (widget);
+  
+  if (!GTK_WIDGET_HAS_FOCUS (widget))
+    gtk_widget_grab_focus (widget);
 
-  if (range->digits >= 0)
+  /* ignore presses when we're already doing something else. */
+  if (range->layout->grab_location != MOUSE_OUTSIDE)
+    return FALSE;
+
+  range->layout->mouse_x = event->x;
+  range->layout->mouse_y = event->y;
+  if (gtk_range_update_mouse_location (range))
+    gtk_widget_queue_draw (widget);
+    
+  if (range->layout->mouse_location == MOUSE_TROUGH  &&
+      (event->button == 1 || event->button == 3))
     {
-      char buffer[64];
+      /* button 1 steps by step increment, as with button 1 on a stepper,
+       * button 3 steps by page increment, as with button 2 on a stepper
+       */
+      GtkScrollType scroll;
+      gdouble click_value;
+      
+      click_value = coord_to_value (range,
+                                    range->orientation == GTK_ORIENTATION_VERTICAL ?
+                                    event->y : event->x);
+      
+      range->trough_click_forward = click_value > range->adjustment->value;
+      range_grab_add (range, MOUSE_TROUGH, event->button);
+      
+      scroll = range_get_scroll_for_grab (range);
+      
+      gtk_range_add_step_timer (range, scroll);
 
-      sprintf (buffer, "%0.*f", range->digits, range->adjustment->value);
-      sscanf (buffer, "%lf", &range->adjustment->value);
+      return TRUE;
     }
-
-  if (old_value != range->adjustment->value)
+  else if ((range->layout->mouse_location == MOUSE_STEPPER_A ||
+            range->layout->mouse_location == MOUSE_STEPPER_B ||
+            range->layout->mouse_location == MOUSE_STEPPER_C ||
+            range->layout->mouse_location == MOUSE_STEPPER_D) &&
+           (event->button == 1 || event->button == 2 || event->button == 3))
     {
-      if (range->policy == GTK_UPDATE_CONTINUOUS)
-       {
-         gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
-       }
+      GdkRectangle *stepper_area;
+      GtkScrollType scroll;
+      
+      range_grab_add (range, range->layout->mouse_location, event->button);
+
+      stepper_area = get_area (range, range->layout->mouse_location);
+      gtk_widget_queue_draw_area (widget,
+                                  stepper_area->x,
+                                  stepper_area->y,
+                                  stepper_area->width,
+                                  stepper_area->height);
+
+      scroll = range_get_scroll_for_grab (range);
+      if (scroll != GTK_SCROLL_NONE)
+        gtk_range_add_step_timer (range, scroll);
+      
+      return TRUE;
+    }
+  else if ((range->layout->mouse_location == MOUSE_TROUGH &&
+            event->button == 2) ||
+           range->layout->mouse_location == MOUSE_SLIDER)
+    {
+      /* Any button can be used to drag the slider, but you can start
+       * dragging the slider with a trough click using button 2;
+       * On button 2 press, we warp the slider to mouse position,
+       * then begin the slider drag.
+       */
+      if (event->button == 2)
+        {
+          gdouble click_value;
+          
+          click_value = coord_to_value (range,
+                                        range->orientation == GTK_ORIENTATION_VERTICAL ?
+                                        event->y : event->x);
+          
+          
+          /* middle button jumps to point */
+          gtk_range_internal_set_value (range, click_value);
+
+          /* Calc layout so we can set slide_initial_slider_position
+           * properly
+           */
+          gtk_range_calc_layout (range);
+        }
+      
+      if (range->orientation == GTK_ORIENTATION_VERTICAL)
+        {
+          range->slide_initial_slider_position = range->layout->slider.y;
+          range->slide_initial_coordinate = event->y;
+        }
       else
-       {
-         _gtk_range_slider_update (range);
-         _gtk_range_clear_background (range);
-
-         if (range->policy == GTK_UPDATE_DELAYED)
-           {
-             gtk_range_remove_timer (range);
-             range->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH,
-                                             (GtkFunction) RANGE_CLASS (range)->timer,
-                                             (gpointer) range);
-           }
-       }
+        {
+          range->slide_initial_slider_position = range->layout->slider.x;
+          range->slide_initial_coordinate = event->x;
+        }
+
+      range_grab_add (range, MOUSE_SLIDER, event->button);
+      
+      return TRUE;
     }
+  
+  return FALSE;
 }
 
-void
-_gtk_range_default_vmotion (GtkRange *range,
-                            gint      xdelta,
-                            gint      ydelta)
+/* During a slide, move the slider as required given new mouse position */
+static void
+update_slider_position (GtkRange *range,
+                        gint      mouse_x,
+                        gint      mouse_y)
 {
-  gdouble old_value;
-  gint top, bottom;
-  gint slider_x, slider_y;
-  gint new_pos;
+  gint delta;
+  gint c;
+  gdouble new_value;
+  
+  if (range->orientation == GTK_ORIENTATION_VERTICAL)
+    delta = mouse_y - range->slide_initial_coordinate;
+  else
+    delta = mouse_x - range->slide_initial_coordinate;
 
-  g_return_if_fail (GTK_IS_RANGE (range));
-  g_return_if_fail (GTK_WIDGET_REALIZED (range));
+  c = range->slide_initial_slider_position + delta;
 
-  range = GTK_RANGE (range);
+  new_value = coord_to_value (range, c);
+  
+  gtk_range_internal_set_value (range, new_value);
+}
 
-  gdk_window_get_position (range->slider, &slider_x, &slider_y);
-  gtk_range_trough_vdims (range, &top, &bottom);
+static gint
+gtk_range_button_release (GtkWidget      *widget,
+                         GdkEventButton *event)
+{
+  GtkRange *range;
 
-  if (bottom == top)
-    return;
+  g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);
 
-  new_pos = slider_y + ydelta;
+  range = GTK_RANGE (widget);
 
-  if (should_invert (range, FALSE))
-    new_pos = (bottom - new_pos) + top;
+  range->layout->mouse_x = event->x;
+  range->layout->mouse_y = event->y;
   
-  if (new_pos < top)
-    new_pos = top;
-  else if (new_pos > bottom)
-    new_pos = bottom;
-
-  old_value = range->adjustment->value;
-  range->adjustment->value = ((range->adjustment->upper -
-                              range->adjustment->lower -
-                              range->adjustment->page_size) *
-                             (new_pos - top) / (bottom - top) +
-                             range->adjustment->lower);
-
-  if (range->digits >= 0)
+  if (range->layout->grab_button == event->button)
     {
-      char buffer[64];
+      GtkScrollType scroll;
+      MouseLocation grab_location;
 
-      sprintf (buffer, "%0.*f", range->digits, range->adjustment->value);
-      sscanf (buffer, "%lf", &range->adjustment->value);
-    }
+      grab_location = range->layout->grab_location;
 
-  if (old_value != range->adjustment->value)
-    {
-      if (range->policy == GTK_UPDATE_CONTINUOUS)
-       {
-         gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
-       }
-      else
-       {
-         _gtk_range_slider_update (range);
-         _gtk_range_clear_background (range);
-
-         if (range->policy == GTK_UPDATE_DELAYED)
-           {
-             gtk_range_remove_timer (range);
-             range->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH,
-                                             (GtkFunction) RANGE_CLASS (range)->timer,
-                                             (gpointer) range);
-           }
-       }
-    }
-}
-
-
-static void
-gtk_range_destroy (GtkObject *object)
-{
-  GtkRange *range;
-
-  g_return_if_fail (object != NULL);
-  g_return_if_fail (GTK_IS_RANGE (object));
-
-  range = GTK_RANGE (object);
-
-  gtk_range_remove_timer (range);
-  if (range->adjustment)
-    {
-      if (range->adjustment)
-       gtk_signal_disconnect_by_data (GTK_OBJECT (range->adjustment),
-                                      (gpointer) range);
-      gtk_object_unref (GTK_OBJECT (range->adjustment));
-      range->adjustment = NULL;
-    }
-
-  (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
-}
-
-static void
-gtk_range_unrealize (GtkWidget *widget)
-{
-  GtkRange *range;
-
-  g_return_if_fail (widget != NULL);
-  g_return_if_fail (GTK_IS_RANGE (widget));
+      scroll = range_get_scroll_for_grab (range);
+      
+      range_grab_remove (range);
+      gtk_range_remove_step_timer (range);
+      
+      /* We only do the move if we're still on top of the button at
+       * release
+       */
+      if (grab_location == range->layout->mouse_location &&
+          scroll != GTK_SCROLL_NONE)
+        {
+          gtk_range_scroll (range, scroll);
+        }
 
-  range = GTK_RANGE (widget);
+      if (grab_location == MOUSE_SLIDER)
+        update_slider_position (range, event->x, event->y);
 
-  if (range->slider)
-    {
-      gdk_window_set_user_data (range->slider, NULL);
-      gdk_window_destroy (range->slider);
-      range->slider = NULL;
-    }
-  if (range->trough)
-    {
-      gdk_window_set_user_data (range->trough, NULL);
-      gdk_window_destroy (range->trough);
-      range->trough = NULL;
-    }
-  if (range->step_forw)
-    {
-      gdk_window_set_user_data (range->step_forw, NULL);
-      gdk_window_destroy (range->step_forw);
-      range->step_forw = NULL;
-    }
-  if (range->step_back)
-    {
-      gdk_window_set_user_data (range->step_back, NULL);
-      gdk_window_destroy (range->step_back);
-      range->step_back = NULL;
+      /* Flush any pending discontinuous/delayed updates */
+      gtk_range_update_value (range);
+      
+      /* Just be lazy about this, if we scrolled it will all redraw anyway,
+       * so no point optimizing the button deactivate case
+       */
+      gtk_widget_queue_draw (widget);
+      
+      return TRUE;
     }
 
-  if (GTK_WIDGET_CLASS (parent_class)->unrealize)
-    (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
-}
-
-static gint
-gtk_range_expose (GtkWidget      *widget,
-                 GdkEventExpose *event)
-{
-  GtkRange *range;
-
-  g_return_val_if_fail (widget != NULL, FALSE);
-  g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE);
-  g_return_val_if_fail (event != NULL, FALSE);
-
-  range = GTK_RANGE (widget);
-
-  /* We should really pass another argument - 
-   *the redrawn area - to all the drawing functions)
-   */
-  if (event->window == range->trough)
-    {
-      _gtk_range_draw_trough (range);
-    }
-  else if (event->window == widget->window)
-    {
-      _gtk_range_draw_background (range); 
-    }
-  else if (event->window == range->slider)
-    {
-      _gtk_range_draw_slider (range);
-    }
-  else if (event->window == range->step_forw)
-    {
-      _gtk_range_draw_step_forw (range);
-    }
-  else if (event->window == range->step_back)
-    {
-      _gtk_range_draw_step_back (range);
-    }
   return FALSE;
 }
 
 static gint
-gtk_range_button_press (GtkWidget      *widget,
-                       GdkEventButton *event)
+gtk_range_scroll_event (GtkWidget      *widget,
+                       GdkEventScroll *event)
 {
   GtkRange *range;
-  gint trough_part;
-  gdouble jump_perc;
 
   g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE);
   g_return_val_if_fail (event != NULL, FALSE);
 
-  if (!GTK_WIDGET_HAS_FOCUS (widget))
-    gtk_widget_grab_focus (widget);
-
-  jump_perc = -1;
   range = GTK_RANGE (widget);
-  if (range->button == 0)
+
+  if (GTK_WIDGET_REALIZED (range))
     {
-      gtk_grab_add (widget);
+      GtkAdjustment *adj = GTK_RANGE (range)->adjustment;
+      gdouble new_value = adj->value + ((event->direction == GDK_SCROLL_UP ||
+                                         event->direction == GDK_SCROLL_RIGHT) ? 
+                                       -adj->page_increment / 2: 
+                                       adj->page_increment / 2);
 
-      range->button = event->button;
-      range->x_click_point = event->x;
-      range->y_click_point = event->y;
+      gtk_range_internal_set_value (range, new_value);
 
-      if (event->window == range->trough)
-       {
-         range->click_child = RANGE_CLASS (range)->trough;
-         
-         if (range->button == 2)
-           trough_part = _gtk_range_trough_click (range, event->x, event->y, &jump_perc);
-         else
-           trough_part = _gtk_range_trough_click (range, event->x, event->y, NULL);
-         
-         range->scroll_type = GTK_SCROLL_NONE;
-         if (trough_part == GTK_TROUGH_START)
-           range->scroll_type = GTK_SCROLL_PAGE_BACKWARD;
-         else if (trough_part == GTK_TROUGH_END)
-           range->scroll_type = GTK_SCROLL_PAGE_FORWARD;
-         else if (trough_part == GTK_TROUGH_JUMP &&
-                  jump_perc >= 0 && jump_perc <= 1)
-           range->scroll_type = GTK_SCROLL_JUMP;
-         
-         if (range->scroll_type != GTK_SCROLL_NONE)
-           {
-             gtk_range_scroll (range, jump_perc);
-             gtk_range_add_timer (range);
-           }
-       }
-      else if (event->window == range->slider)
-       {
-         range->click_child = RANGE_CLASS (range)->slider;
-         range->scroll_type = GTK_SCROLL_NONE;
-       }
-      else if (event->window == range->step_forw ||
-              event->window == range->step_back)
-       {
-         gboolean back = (event->window == range->step_back);
-         
-         if (range->button == 3)
-           {
-             range->scroll_type = GTK_SCROLL_JUMP;
-             gtk_range_scroll (range, back ? 0.0 : 1.0);
-           }
-         else
-           {
-             range->click_child =
-               back ? RANGE_CLASS (range)->step_back
-                    : RANGE_CLASS (range)->step_forw;
-
-             if (range->button == 2)
-               range->scroll_type =
-                 back ? GTK_SCROLL_PAGE_BACKWARD : GTK_SCROLL_PAGE_FORWARD;
-             else
-               range->scroll_type =
-                 back ? GTK_SCROLL_STEP_BACKWARD : GTK_SCROLL_STEP_FORWARD;
-
-             gtk_range_scroll (range, -1);
-             gtk_range_add_timer (range);
-             
-             if (back)
-               _gtk_range_draw_step_back (range);
-             else
-               _gtk_range_draw_step_forw (range);
-           }
-       }
+      /* Policy DELAYED makes sense with scroll events,
+       * but DISCONTINUOUS doesn't, so we update immediately
+       * for DISCONTINOUS
+       */
+      if (range->update_policy == GTK_UPDATE_DISCONTINUOUS)
+        gtk_range_update_value (range);
     }
 
   return TRUE;
 }
 
 static gint
-gtk_range_button_release (GtkWidget      *widget,
-                         GdkEventButton *event)
+gtk_range_motion_notify (GtkWidget      *widget,
+                        GdkEventMotion *event)
 {
   GtkRange *range;
+  gint x, y;
 
   g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE);
   g_return_val_if_fail (event != NULL, FALSE);
 
   range = GTK_RANGE (widget);
 
-  if (range->button == event->button)
-    {
-      gtk_grab_remove (widget);
-
-      range->button = 0;
-      range->x_click_point = -1;
-      range->y_click_point = -1;
-
-      if (range->click_child == RANGE_CLASS (range)->slider)
-       {
-         if (range->policy == GTK_UPDATE_DELAYED)
-           gtk_range_remove_timer (range);
+  gdk_window_get_pointer (widget->window, &x, &y, NULL);
+  
+  range->layout->mouse_x = x;
+  range->layout->mouse_y = y;
 
-         if ((range->policy != GTK_UPDATE_CONTINUOUS) &&
-             (range->old_value != range->adjustment->value))
-           gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
-       }
-      else if ((range->click_child == RANGE_CLASS (range)->trough) ||
-              (range->click_child == RANGE_CLASS (range)->step_forw) ||
-              (range->click_child == RANGE_CLASS (range)->step_back))
-       {
-         gtk_range_remove_timer (range);
-
-         if ((range->policy != GTK_UPDATE_CONTINUOUS) &&
-             (range->old_value != range->adjustment->value))
-           gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
-
-         if (range->click_child == RANGE_CLASS (range)->step_forw)
-           {
-             range->click_child = 0;
-             _gtk_range_draw_step_forw (range);
-           }
-         else if (range->click_child == RANGE_CLASS (range)->step_back)
-           {
-             range->click_child = 0;
-             _gtk_range_draw_step_back (range);
-           }
-       }
+  if (gtk_range_update_mouse_location (range))
+    gtk_widget_queue_draw (widget);
 
-      range->click_child = 0;
-    }
+  if (range->layout->grab_location == MOUSE_SLIDER)
+    update_slider_position (range, event->x, event->y);
 
-  return TRUE;
+  /* We handled the event if the mouse was in the range_rect */
+  return range->layout->mouse_location != MOUSE_OUTSIDE;
 }
 
 static gint
-gtk_range_scroll_event (GtkWidget      *widget,
-                       GdkEventScroll *event)
+gtk_range_enter_notify (GtkWidget        *widget,
+                       GdkEventCrossing *event)
 {
   GtkRange *range;
 
@@ -1114,22 +1101,18 @@ gtk_range_scroll_event (GtkWidget      *widget,
 
   range = GTK_RANGE (widget);
 
-  if (GTK_WIDGET_REALIZED (range))
-    {
-      GtkAdjustment *adj = GTK_RANGE (range)->adjustment;
-      gdouble new_value = adj->value + ((event->direction == GDK_SCROLL_UP) ? 
-                                       -adj->page_increment / 2: 
-                                       adj->page_increment / 2);
-      new_value = CLAMP (new_value, adj->lower, adj->upper - adj->page_size);
-      gtk_adjustment_set_value (adj, new_value);
-    }
+  range->layout->mouse_x = event->x;
+  range->layout->mouse_y = event->y;
 
+  if (gtk_range_update_mouse_location (range))
+    gtk_widget_queue_draw (widget);
+  
   return TRUE;
 }
 
 static gint
-gtk_range_motion_notify (GtkWidget      *widget,
-                        GdkEventMotion *event)
+gtk_range_leave_notify (GtkWidget        *widget,
+                       GdkEventCrossing *event)
 {
   GtkRange *range;
 
@@ -1138,718 +1121,955 @@ gtk_range_motion_notify (GtkWidget      *widget,
 
   range = GTK_RANGE (widget);
 
-  if (range->click_child == RANGE_CLASS (range)->slider)
-    {
-      GdkModifierType mods;
-      gint x, y, mask, x2, y2;
-
-      gdk_window_get_pointer (range->trough, &x, &y, &mods);
-      gdk_window_get_position (range->slider, &x2, &y2);
-
-      x -= x2;
-      y -= y2;
-
-      switch (range->button)
-       {
-       case 1:
-         mask = GDK_BUTTON1_MASK;
-         break;
-       case 2:
-         mask = GDK_BUTTON2_MASK;
-         break;
-       case 3:
-         mask = GDK_BUTTON3_MASK;
-         break;
-       default:
-         mask = 0;
-         break;
-       }
-
-      if (mods & mask)
-       {
-         if (RANGE_CLASS (range)->motion)
-           (* RANGE_CLASS (range)->motion) (range, x - range->x_click_point, y - range->y_click_point);
-       }
-    }
+  range->layout->mouse_x = -1;
+  range->layout->mouse_y = -1;
 
+  if (gtk_range_update_mouse_location (range))
+    gtk_widget_queue_draw (widget);
+  
   return TRUE;
 }
 
 static void
-gtk_range_move_slider (GtkRange     *range,
-                       GtkScrollType scroll,
-                       GtkTroughType pos)
+gtk_range_adjustment_changed (GtkAdjustment *adjustment,
+                             gpointer       data)
 {
-  if (scroll != GTK_SCROLL_NONE)
-    {
-      range->scroll_type = scroll;
+  GtkRange *range;
 
-      gtk_range_scroll (range, -1);
-      if (range->old_value != range->adjustment->value)
-        {
-          gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
-          switch (range->scroll_type)
-            {
-            case GTK_SCROLL_STEP_LEFT:
-              if (should_invert (range, TRUE))
-                _gtk_range_draw_step_forw (range);
-              else
-                _gtk_range_draw_step_back (range);
-              break;
-                    
-            case GTK_SCROLL_STEP_UP:
-              if (should_invert (range, FALSE))
-                _gtk_range_draw_step_forw (range);
-              else
-                _gtk_range_draw_step_back (range);
-              break;
-
-            case GTK_SCROLL_STEP_RIGHT:
-              if (should_invert (range, TRUE))
-                _gtk_range_draw_step_back (range);
-              else
-                _gtk_range_draw_step_forw (range);
-              break;
-                    
-            case GTK_SCROLL_STEP_DOWN:
-              if (should_invert (range, FALSE))
-                _gtk_range_draw_step_back (range);
-              else
-                _gtk_range_draw_step_forw (range);
-              break;
-                  
-            case GTK_SCROLL_STEP_BACKWARD:
-              _gtk_range_draw_step_back (range);
-              break;
-                  
-            case GTK_SCROLL_STEP_FORWARD:
-              _gtk_range_draw_step_forw (range);
-              break;
-            }
-        }
-    }
+  g_return_if_fail (adjustment != NULL);
+  g_return_if_fail (data != NULL);
 
-  if (pos != GTK_TROUGH_NONE)
-    {
-      if (pos == GTK_TROUGH_START)
-        range->adjustment->value = range->adjustment->lower;
-      else if (pos == GTK_TROUGH_END)
-        range->adjustment->value =
-          range->adjustment->upper - range->adjustment->page_size;
-      
-      if (range->old_value != range->adjustment->value)
-        {
-          gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment),
-                                   "value_changed");
-          
-          _gtk_range_slider_update (range);
-          _gtk_range_clear_background (range);
-        }
-    }
+  range = GTK_RANGE (data);
+
+  range->need_recalc = TRUE;
+  gtk_widget_queue_draw (GTK_WIDGET (range));
+
+  /* Note that we don't round off to range->round_digits here.
+   * that's because it's really broken to change a value
+   * in response to a change signal on that value; round_digits
+   * is therefore defined to be a filter on what the GtkRange
+   * can input into the adjustment, not a filter that the GtkRange
+   * will enforce on the adjustment.
+   */
 }
 
-static gint
-gtk_range_enter_notify (GtkWidget        *widget,
-                       GdkEventCrossing *event)
+static void
+gtk_range_adjustment_value_changed (GtkAdjustment *adjustment,
+                                   gpointer       data)
 {
   GtkRange *range;
 
-  g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE);
-  g_return_val_if_fail (event != NULL, FALSE);
-
-  range = GTK_RANGE (widget);
-
-  if (event->window == range->trough)
-    {
-      range->in_child = RANGE_CLASS (range)->trough;
-    }
-  else if (event->window == range->slider)
-    {
-      range->in_child = RANGE_CLASS (range)->slider;
-
-      if ((range->click_child == 0) ||
-         (range->click_child == RANGE_CLASS (range)->trough))
-       _gtk_range_draw_slider (range);
-    }
-  else if (event->window == range->step_forw)
-    {
-      range->in_child = RANGE_CLASS (range)->step_forw;
+  g_return_if_fail (adjustment != NULL);
+  g_return_if_fail (data != NULL);
 
-      if ((range->click_child == 0) ||
-         (range->click_child == RANGE_CLASS (range)->trough))
-       _gtk_range_draw_step_forw (range);
-    }
-  else if (event->window == range->step_back)
-    {
-      range->in_child = RANGE_CLASS (range)->step_back;
+  range = GTK_RANGE (data);
 
-      if ((range->click_child == 0) ||
-         (range->click_child == RANGE_CLASS (range)->trough))
-       _gtk_range_draw_step_back (range);
-    }
+  range->need_recalc = TRUE;
+  gtk_widget_queue_draw (GTK_WIDGET (range));
 
-  return TRUE;
+  /* Note that we don't round off to range->round_digits here.
+   * that's because it's really broken to change a value
+   * in response to a change signal on that value; round_digits
+   * is therefore defined to be a filter on what the GtkRange
+   * can input into the adjustment, not a filter that the GtkRange
+   * will enforce on the adjustment.
+   */
 }
 
-static gint
-gtk_range_leave_notify (GtkWidget        *widget,
-                       GdkEventCrossing *event)
+static void
+gtk_range_style_set (GtkWidget *widget,
+                     GtkStyle  *previous_style)
 {
   GtkRange *range;
 
-  g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE);
-  g_return_val_if_fail (event != NULL, FALSE);
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_RANGE (widget));
 
   range = GTK_RANGE (widget);
 
-  range->in_child = 0;
-
-  if (event->window == range->trough)
-    {
-    }
-  else if (event->window == range->slider)
-    {
-      if ((range->click_child == 0) ||
-         (range->click_child == RANGE_CLASS (range)->trough))
-       _gtk_range_draw_slider (range);
-    }
-  else if (event->window == range->step_forw)
-    {
-      if ((range->click_child == 0) ||
-         (range->click_child == RANGE_CLASS (range)->trough))
-       _gtk_range_draw_step_forw (range);
-    }
-  else if (event->window == range->step_back)
-    {
-      if ((range->click_child == 0) ||
-         (range->click_child == RANGE_CLASS (range)->trough))
-       _gtk_range_draw_step_back (range);
-    }
+  range->need_recalc = TRUE;
 
-  return TRUE;
+  (* GTK_WIDGET_CLASS (parent_class)->style_set) (widget, previous_style);
 }
 
 static void
-gtk_real_range_draw_trough (GtkRange *range)
+step_back (GtkRange *range)
 {
-  g_return_if_fail (GTK_IS_RANGE (range));
-
-  if (range->trough)
-     {
-       gtk_paint_box (GTK_WIDGET (range)->style, range->trough,
-                      GTK_STATE_ACTIVE, GTK_SHADOW_IN,
-                      NULL, GTK_WIDGET(range), "trough",
-                      0, 0, -1, -1);
-       if (GTK_WIDGET_HAS_FOCUS (range))
-         gtk_paint_focus (GTK_WIDGET (range)->style,
-                         range->trough,
-                          NULL, GTK_WIDGET(range), "trough",
-                         0, 0, -1, -1);
-    }
+  gdouble newval;
+  
+  newval = range->adjustment->value - range->adjustment->step_increment;
+  gtk_range_internal_set_value (range, newval);
 }
 
 static void
-gtk_real_range_draw_slider (GtkRange *range)
-{
-  GtkStateType state_type;
-   
-  g_return_if_fail (GTK_IS_RANGE (range));
-   
-  if (range->slider)
-    {
-      if ((range->in_child == RANGE_CLASS (range)->slider) ||
-         (range->click_child == RANGE_CLASS (range)->slider))
-       state_type = GTK_STATE_PRELIGHT;
-      else
-       state_type = GTK_STATE_NORMAL;
-      gtk_paint_box (GTK_WIDGET (range)->style, range->slider,
-                    state_type, GTK_SHADOW_OUT,
-                    NULL, GTK_WIDGET (range), "slider",
-                    0, 0, -1, -1);
-    }
-}
-
-static gint
-gtk_real_range_timer (GtkRange *range)
+step_forward (GtkRange *range)
 {
-  gint return_val;
-
-  GDK_THREADS_ENTER ();
-
-  return_val = TRUE;
-  if (range->click_child == RANGE_CLASS (range)->slider)
-    {
-      if (range->policy == GTK_UPDATE_DELAYED)
-       gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
-      return_val = FALSE;
-    }
-  else
-    {
-      GdkModifierType mods, mask;
-
-      if (!range->timer)
-       {
-         return_val = FALSE;
-         if (range->need_timer)
-           range->timer = gtk_timeout_add (SCROLL_TIMER_LENGTH,
-                                           (GtkFunction) RANGE_CLASS (range)->timer,
-                                           (gpointer) range);
-         else
-           {
-             GDK_THREADS_LEAVE ();
-             return FALSE;
-           }
-         range->need_timer = FALSE;
-       }
+  gdouble newval;
 
-      switch (range->button)
-       {
-       case 1:
-         mask = GDK_BUTTON1_MASK;
-         break;
-       case 2:
-         mask = GDK_BUTTON2_MASK;
-         break;
-       case 3:
-         mask = GDK_BUTTON3_MASK;
-         break;
-       default:
-         mask = 0;
-         break;
-       }
+  newval = range->adjustment->value + range->adjustment->step_increment;
 
-      gdk_window_get_pointer (range->slider, NULL, NULL, &mods);
+  gtk_range_internal_set_value (range, newval);
+}
 
-      if (mods & mask)
-       return_val = gtk_range_scroll (range, -1);
-    }
 
-  GDK_THREADS_LEAVE ();
+static void
+page_back (GtkRange *range)
+{
+  gdouble newval;
 
-  return return_val;
+  newval = range->adjustment->value - range->adjustment->page_increment;
+  gtk_range_internal_set_value (range, newval);
 }
 
-static gint
-gtk_range_scroll (GtkRange  *range,
-                 gdouble    jump_perc)
+static void
+page_forward (GtkRange *range)
 {
-  gdouble new_value;
-  gint return_val;
-  GtkScrollType scroll_type;
-  
-  g_return_val_if_fail (GTK_IS_RANGE (range), FALSE);
+  gdouble newval;
 
-  new_value = range->adjustment->value;
-  return_val = TRUE;
+  newval = range->adjustment->value + range->adjustment->page_increment;
 
-  /* Translate visual to logical */
+  gtk_range_internal_set_value (range, newval);
+}
 
-  scroll_type = range->scroll_type;
-  switch (scroll_type)
+static void
+gtk_range_scroll (GtkRange     *range,
+                  GtkScrollType scroll)
+{
+  switch (scroll)
     {
-    case GTK_SCROLL_STEP_UP:
-      if (should_invert (range, FALSE))
-        scroll_type = GTK_SCROLL_STEP_FORWARD;
+    case GTK_SCROLL_STEP_LEFT:
+      if (should_invert (range))
+        step_forward (range);
       else
-        scroll_type = GTK_SCROLL_STEP_BACKWARD;
+        step_back (range);
       break;
-
-    case GTK_SCROLL_STEP_DOWN:
-      if (should_invert (range, FALSE))
-        scroll_type = GTK_SCROLL_STEP_BACKWARD;
+                    
+    case GTK_SCROLL_STEP_UP:
+      if (should_invert (range))
+        step_forward (range);
       else
-        scroll_type = GTK_SCROLL_STEP_FORWARD;
+        step_back (range);
       break;
 
-    case GTK_SCROLL_PAGE_UP:
-      if (should_invert (range, FALSE))
-        scroll_type = GTK_SCROLL_PAGE_FORWARD;
+    case GTK_SCROLL_STEP_RIGHT:
+      if (should_invert (range))
+        step_back (range);
       else
-        scroll_type = GTK_SCROLL_PAGE_BACKWARD;
+        step_forward (range);
       break;
-
-    case GTK_SCROLL_PAGE_DOWN:
-      if (should_invert (range, FALSE))
-        scroll_type = GTK_SCROLL_PAGE_BACKWARD;
+                    
+    case GTK_SCROLL_STEP_DOWN:
+      if (should_invert (range))
+        step_back (range);
       else
-        scroll_type = GTK_SCROLL_PAGE_FORWARD;
+        step_forward (range);
       break;
-
-    case GTK_SCROLL_STEP_LEFT:
-      if (should_invert (range, TRUE))
-        scroll_type = GTK_SCROLL_STEP_FORWARD;
-      else
-        scroll_type = GTK_SCROLL_STEP_BACKWARD;
+                  
+    case GTK_SCROLL_STEP_BACKWARD:
+      step_back (range);
       break;
-
-    case GTK_SCROLL_STEP_RIGHT:
-      if (should_invert (range, TRUE))
-        scroll_type = GTK_SCROLL_STEP_BACKWARD;
-      else
-        scroll_type = GTK_SCROLL_STEP_FORWARD;
+                  
+    case GTK_SCROLL_STEP_FORWARD:
+      step_forward (range);
       break;
 
     case GTK_SCROLL_PAGE_LEFT:
-      if (should_invert (range, TRUE))
-        scroll_type = GTK_SCROLL_PAGE_FORWARD;
+      if (should_invert (range))
+        page_forward (range);
       else
-        scroll_type = GTK_SCROLL_PAGE_BACKWARD;
+        page_back (range);
       break;
-
-    case GTK_SCROLL_PAGE_RIGHT:
-      if (should_invert (range, TRUE))
-        scroll_type = GTK_SCROLL_PAGE_BACKWARD;
+                    
+    case GTK_SCROLL_PAGE_UP:
+      if (should_invert (range))
+        page_forward (range);
       else
-        scroll_type = GTK_SCROLL_PAGE_FORWARD;
+        page_back (range);
       break;
 
-    default:
+    case GTK_SCROLL_PAGE_RIGHT:
+      if (should_invert (range))
+        page_back (range);
+      else
+        page_forward (range);
       break;
-    }
-  
-  switch (scroll_type)
-    {
-    case GTK_SCROLL_NONE:
+                    
+    case GTK_SCROLL_PAGE_DOWN:
+      if (should_invert (range))
+        page_back (range);
+      else
+        page_forward (range);
       break;
-      
-    case GTK_SCROLL_JUMP:
-      if (jump_perc >= 0 && jump_perc <= 1)
-       {
-         new_value = (range->adjustment->lower +
-                      (range->adjustment->upper - range->adjustment->page_size -
-                       range->adjustment->lower) * jump_perc);
-       }
+                  
+    case GTK_SCROLL_PAGE_BACKWARD:
+      page_back (range);
       break;
-      
-    case GTK_SCROLL_STEP_BACKWARD:
-      new_value -= range->adjustment->step_increment;
-      if (new_value <= range->adjustment->lower)
-       {
-         new_value = range->adjustment->lower;
-         return_val = FALSE;
-         range->timer = 0;
-       }
+                  
+    case GTK_SCROLL_PAGE_FORWARD:
+      page_forward (range);
       break;
 
-    case GTK_SCROLL_STEP_FORWARD:
-      new_value += range->adjustment->step_increment;
-      if (new_value >= (range->adjustment->upper - range->adjustment->page_size))
-       {
-         new_value = range->adjustment->upper - range->adjustment->page_size;
-         return_val = FALSE;
-         range->timer = 0;
-       }
+    case GTK_SCROLL_START:
+      gtk_range_internal_set_value (range,
+                                    range->adjustment->lower);
       break;
 
-    case GTK_SCROLL_PAGE_BACKWARD:
-      new_value -= range->adjustment->page_increment;
-      if (new_value <= range->adjustment->lower)
-       {
-         new_value = range->adjustment->lower;
-         return_val = FALSE;
-         range->timer = 0;
-       }
+    case GTK_SCROLL_END:
+      gtk_range_internal_set_value (range,
+                                    range->adjustment->upper - range->adjustment->page_size);
       break;
 
-    case GTK_SCROLL_PAGE_FORWARD:
-      new_value += range->adjustment->page_increment;
-      if (new_value >= (range->adjustment->upper - range->adjustment->page_size))
-       {
-         new_value = range->adjustment->upper - range->adjustment->page_size;
-         return_val = FALSE;
-         range->timer = 0;
-       }
+    case GTK_SCROLL_JUMP:
+      /* Used by CList, range doesn't use it. */
       break;
 
-    case GTK_SCROLL_STEP_UP:
-    case GTK_SCROLL_STEP_DOWN:
-    case GTK_SCROLL_PAGE_UP:
-    case GTK_SCROLL_PAGE_DOWN:
-    case GTK_SCROLL_STEP_LEFT:
-    case GTK_SCROLL_STEP_RIGHT:
-    case GTK_SCROLL_PAGE_LEFT:
-    case GTK_SCROLL_PAGE_RIGHT:
-      g_assert_not_reached ();
+    case GTK_SCROLL_NONE:
       break;
-
     }
+}
+
+static void
+gtk_range_move_slider (GtkRange     *range,
+                       GtkScrollType scroll)
+{
+  gtk_range_scroll (range, scroll);
+
+  /* Policy DELAYED makes sense with key events,
+   * but DISCONTINUOUS doesn't, so we update immediately
+   * for DISCONTINOUS
+   */
+  if (range->update_policy == GTK_UPDATE_DISCONTINUOUS)
+    gtk_range_update_value (range);
+}
+
+static void
+gtk_range_get_props (GtkRange  *range,
+                     gint      *slider_width,
+                     gint      *stepper_size,
+                     gint      *trough_border,
+                     gint      *stepper_spacing)
+{
+  GtkWidget *widget =  GTK_WIDGET (range);
+  gint tmp_slider_width, tmp_stepper_size, tmp_trough_border, tmp_stepper_spacing;
   
-  if (new_value != range->adjustment->value)
-    {
-      range->adjustment->value = new_value;
+  gtk_widget_style_get (widget,
+                        "slider_width", &tmp_slider_width,
+                        "trough_border", &tmp_trough_border,
+                        "stepper_size", &tmp_stepper_size,
+                        "stepper_spacing", &tmp_stepper_spacing,
+                        NULL);
+  
+  if (slider_width)
+    *slider_width = tmp_slider_width;
 
-      if ((range->policy == GTK_UPDATE_CONTINUOUS) ||
-         (!return_val && (range->policy == GTK_UPDATE_DELAYED)))
-       {
-         gtk_signal_emit_by_name (GTK_OBJECT (range->adjustment), "value_changed");
-       }
-      else
-       {
-         _gtk_range_slider_update (range);
-         _gtk_range_clear_background (range);
-       }
-    }
+  if (trough_border)
+    *trough_border = tmp_trough_border;
+
+  if (stepper_size)
+    *stepper_size = tmp_stepper_size;
 
-  return return_val;
+  if (stepper_spacing)
+    *stepper_spacing = tmp_stepper_spacing;
 }
 
+#define POINT_IN_RECT(xcoord, ycoord, rect) \
+ ((xcoord) >= (rect).x &&                   \
+  (xcoord) <  ((rect).x + (rect).width) &&  \
+  (ycoord) >= (rect).y &&                   \
+  (ycoord) <  ((rect).y + (rect).height))
 
+/* Update mouse location, return TRUE if it changes */
 static gboolean
-gtk_range_timer_1st_time (GtkRange *range)
+gtk_range_update_mouse_location (GtkRange *range)
 {
-  /*
-   * If the real timeout function succeeds and the timeout is still set,
-   * replace it with a quicker one so successive scrolling goes faster.
-   */
-  gtk_object_ref (GTK_OBJECT (range));
+  gint x, y;
+  MouseLocation old;
+  GtkWidget *widget;
 
-  if (RANGE_CLASS (range)->timer (range))
-    {
-      if (range->timer)
-       {
-         /* We explicitely remove ourselves here in the paranoia
-          * that due to things happening above in the callback
-          * above, we might have been removed, and another added.
-          */
-         g_source_remove (range->timer);
-         range->timer = gtk_timeout_add (SCROLL_LATER_DELAY,
-                                         (GtkFunction) RANGE_CLASS (range)->timer,
-                                         range);
-       }
-    }
+  widget = GTK_WIDGET (range);
   
-  gtk_object_unref (GTK_OBJECT (range));
+  old = range->layout->mouse_location;
   
-  return FALSE;  /* don't keep calling this function */
+  x = range->layout->mouse_x;
+  y = range->layout->mouse_y;
+
+  if (range->layout->grab_location != MOUSE_OUTSIDE)
+    range->layout->mouse_location = range->layout->grab_location;
+  else if (POINT_IN_RECT (x, y, range->layout->stepper_a))
+    range->layout->mouse_location = MOUSE_STEPPER_A;
+  else if (POINT_IN_RECT (x, y, range->layout->stepper_b))
+    range->layout->mouse_location = MOUSE_STEPPER_B;
+  else if (POINT_IN_RECT (x, y, range->layout->stepper_c))
+    range->layout->mouse_location = MOUSE_STEPPER_C;
+  else if (POINT_IN_RECT (x, y, range->layout->stepper_d))
+    range->layout->mouse_location = MOUSE_STEPPER_D;
+  else if (POINT_IN_RECT (x, y, range->layout->slider))
+    range->layout->mouse_location = MOUSE_SLIDER;
+  else if (POINT_IN_RECT (x, y, range->layout->trough))
+    range->layout->mouse_location = MOUSE_TROUGH;
+  else if (POINT_IN_RECT (x, y, widget->allocation))
+    range->layout->mouse_location = MOUSE_WIDGET;
+  else
+    range->layout->mouse_location = MOUSE_OUTSIDE;
+
+  return old != range->layout->mouse_location;
 }
 
+/* Clamp rect, border inside widget->allocation, such that we prefer
+ * to take space from border not rect in all directions, and prefer to
+ * give space to border over rect in one direction.
+ */
 static void
-gtk_range_add_timer (GtkRange *range)
+clamp_dimensions (GtkWidget    *widget,
+                  GdkRectangle *rect,
+                  GtkBorder    *border,
+                  gboolean      border_expands_horizontally)
 {
-  g_return_if_fail (GTK_IS_RANGE (range));
+  gint extra, shortage;
+  
+  g_return_if_fail (rect->x == 0);
+  g_return_if_fail (rect->y == 0);  
+  g_return_if_fail (rect->width >= 0);
+  g_return_if_fail (rect->height >= 0);
+
+  /* Width */
+  
+  extra = widget->allocation.width - border->left - border->right - rect->width;
+  if (extra > 0)
+    {
+      if (border_expands_horizontally)
+        {
+          border->left += extra / 2;
+          border->right += extra / 2 + extra % 2;
+        }
+      else
+        {
+          rect->width += extra;
+        }
+    }
+  
+  /* See if we can fit rect, if not kill the border */
+  shortage = rect->width - widget->allocation.width;
+  if (shortage > 0)
+    {
+      rect->width = widget->allocation.width;
+      /* lose the border */
+      border->left = 0;
+      border->right = 0;
+    }
+  else
+    {
+      /* See if we can fit rect with borders */
+      shortage = rect->width + border->left + border->right -
+        widget->allocation.width;
+      if (shortage > 0)
+        {
+          /* Shrink borders */
+          border->left -= shortage / 2;
+          border->right -= shortage / 2 + shortage % 2;
+        }
+    }
 
-  if (!range->timer)
+  /* Height */
+  
+  extra = widget->allocation.height - border->top - border->bottom - rect->height;
+  if (extra > 0)
     {
-      range->need_timer = TRUE;
-      range->timer = gtk_timeout_add (SCROLL_INITIAL_DELAY,
-                                     (GtkFunction) gtk_range_timer_1st_time,
-                                     range);
+      if (border_expands_horizontally)
+        {
+          /* don't expand border vertically */
+          rect->height += extra;
+        }
+      else
+        {
+          border->top += extra / 2;
+          border->bottom += extra / 2 + extra % 2;
+        }
+    }
+  
+  /* See if we can fit rect, if not kill the border */
+  shortage = rect->height - widget->allocation.height;
+  if (shortage > 0)
+    {
+      rect->height = widget->allocation.height;
+      /* lose the border */
+      border->top = 0;
+      border->bottom = 0;
+    }
+  else
+    {
+      /* See if we can fit rect with borders */
+      shortage = rect->height + border->top + border->bottom -
+        widget->allocation.height;
+      if (shortage > 0)
+        {
+          /* Shrink borders */
+          border->top -= shortage / 2;
+          border->bottom -= shortage / 2 + shortage % 2;
+        }
     }
 }
 
 static void
-gtk_range_remove_timer (GtkRange *range)
+gtk_range_calc_request (GtkRange      *range,
+                        gint           slider_width,
+                        gint           stepper_size,
+                        gint           trough_border,
+                        gint           stepper_spacing,
+                        GdkRectangle  *range_rect,
+                        GtkBorder     *border,
+                        gint          *n_steppers_p,
+                        gint          *slider_length_p)
 {
-  g_return_if_fail (GTK_IS_RANGE (range));
+  gint slider_length;
+  gint n_steppers;
+  
+  border->left = 0;
+  border->right = 0;
+  border->top = 0;
+  border->bottom = 0;
 
-  if (range->timer)
+  if (GTK_RANGE_GET_CLASS (range)->get_range_border)
+    (* GTK_RANGE_GET_CLASS (range)->get_range_border) (range, border);
+  
+  n_steppers = 0;
+  if (range->has_stepper_a)
+    n_steppers += 1;
+  if (range->has_stepper_b)
+    n_steppers += 1;
+  if (range->has_stepper_c)
+    n_steppers += 1;
+  if (range->has_stepper_d)
+    n_steppers += 1;
+
+  slider_length = range->min_slider_size;
+
+  range_rect->x = 0;
+  range_rect->y = 0;
+  
+  /* We never expand to fill available space in the small dimension
+   * (i.e. vertical scrollbars are always a fixed width)
+   */
+  if (range->orientation == GTK_ORIENTATION_VERTICAL)
+    {
+      range_rect->width = trough_border * 2 + slider_width;
+      range_rect->height = stepper_size * n_steppers + stepper_spacing * 2 + trough_border * 2 + slider_length;
+    }
+  else
     {
-      gtk_timeout_remove (range->timer);
-      range->timer = 0;
+      range_rect->width = stepper_size * n_steppers + stepper_spacing * 2 + trough_border * 2 + slider_length;
+      range_rect->height = trough_border * 2 + slider_width;
     }
-  range->need_timer = FALSE;
+
+  if (n_steppers_p)
+    *n_steppers_p = n_steppers;
+
+  if (slider_length_p)
+    *slider_length_p = slider_length;
 }
 
 static void
-gtk_range_adjustment_changed (GtkAdjustment *adjustment,
-                             gpointer       data)
+gtk_range_calc_layout (GtkRange *range)
 {
-  GtkRange *range;
+  gint slider_width, stepper_size, trough_border, stepper_spacing;
+  gint slider_length;
+  GtkBorder border;
+  gint n_steppers;
+  GdkRectangle range_rect;
+  GtkRangeLayout *layout;
+  GtkWidget *widget;
+  
+  if (!range->need_recalc)
+    return;
 
-  g_return_if_fail (adjustment != NULL);
-  g_return_if_fail (data != NULL);
+  /* If we have a too-small allocation, we prefer the steppers over
+   * the trough/slider, probably the steppers are a more useful
+   * feature in small spaces.
+   *
+   * Also, we prefer to draw the range itself rather than the border
+   * areas if there's a conflict, since the borders will be decoration
+   * not controls. Though this depends on subclasses cooperating by
+   * not drawing on range->range_rect.
+   */
 
-  range = GTK_RANGE (data);
+  widget = GTK_WIDGET (range);
+  layout = range->layout;
+  
+  gtk_range_get_props (range,
+                       &slider_width, &stepper_size, &trough_border, &stepper_spacing);
 
-  if (((range->old_lower != adjustment->lower) ||
-       (range->old_upper != adjustment->upper) ||
-       (range->old_page_size != adjustment->page_size)) &&
-      (range->old_value == adjustment->value))
+  gtk_range_calc_request (range, 
+                          slider_width, stepper_size, trough_border, stepper_spacing,
+                          &range_rect, &border, &n_steppers, &slider_length);
+  
+  /* We never expand to fill available space in the small dimension
+   * (i.e. vertical scrollbars are always a fixed width)
+   */
+  if (range->orientation == GTK_ORIENTATION_VERTICAL)
     {
-      if ((adjustment->lower == adjustment->upper) ||
-         (range->old_lower == (range->old_upper - range->old_page_size)))
-       {
-         adjustment->value = adjustment->lower;
-         gtk_signal_emit_by_name (GTK_OBJECT (adjustment), "value_changed");
-       }
+      clamp_dimensions (widget, &range_rect, &border, TRUE);
     }
-
-  if ((range->old_value != adjustment->value) ||
-      (range->old_lower != adjustment->lower) ||
-      (range->old_upper != adjustment->upper) ||
-      (range->old_page_size != adjustment->page_size))
+  else
     {
-      _gtk_range_slider_update (range);
-      _gtk_range_clear_background (range);
-
-      range->old_value = adjustment->value;
-      range->old_lower = adjustment->lower;
-      range->old_upper = adjustment->upper;
-      range->old_page_size = adjustment->page_size;
+      clamp_dimensions (widget, &range_rect, &border, FALSE);
     }
-}
+  
+  range_rect.x = border.left;
+  range_rect.y = border.top;
+  
+  range->range_rect = range_rect;
+  
+  if (range->orientation == GTK_ORIENTATION_VERTICAL)
+    {
+      gint stepper_width, stepper_height;
 
-static void
-gtk_range_adjustment_value_changed (GtkAdjustment *adjustment,
-                                   gpointer       data)
-{
-  GtkRange *range;
+      /* Steppers are the width of the range, and stepper_size in
+       * height, or if we don't have enough height, divided equally
+       * among available space.
+       */
+      stepper_width = range_rect.width - trough_border * 2;
 
-  g_return_if_fail (adjustment != NULL);
-  g_return_if_fail (data != NULL);
+      if (stepper_width < 1)
+        stepper_width = range_rect.width; /* screw the trough border */
 
-  range = GTK_RANGE (data);
+      if (n_steppers == 0)
+        stepper_height = 0; /* avoid divide by n_steppers */
+      else
+        stepper_height = MIN (stepper_size, (range_rect.height / n_steppers));
 
-  if (range->old_value != adjustment->value)
-    {
-      _gtk_range_slider_update (range);
-      _gtk_range_clear_background (range);
+      /* Stepper A */
+      
+      layout->stepper_a.x = range_rect.x + trough_border;
+      layout->stepper_a.y = range_rect.y + trough_border;
 
-      range->old_value = adjustment->value;
-    }
-}
+      if (range->has_stepper_a)
+        {
+          layout->stepper_a.width = stepper_width;
+          layout->stepper_a.height = stepper_height;
+        }
+      else
+        {
+          layout->stepper_a.width = 0;
+          layout->stepper_a.height = 0;
+        }
 
+      /* Stepper B */
+      
+      layout->stepper_b.x = layout->stepper_a.x;
+      layout->stepper_b.y = layout->stepper_a.y + layout->stepper_a.height;
 
-static void
-gtk_range_trough_hdims (GtkRange *range,
-                       gint     *left,
-                       gint     *right)
-{
-  gint trough_width;
-  gint slider_length;
-  gint tmp_width;
-  gint tleft;
-  gint tright;
-  gint stepper_spacing;
-  gint trough_border;
+      if (range->has_stepper_b)
+        {
+          layout->stepper_b.width = stepper_width;
+          layout->stepper_b.height = stepper_height;
+        }
+      else
+        {
+          layout->stepper_b.width = 0;
+          layout->stepper_b.height = 0;
+        }
 
-  g_return_if_fail (range != NULL);
+      /* Stepper D */
+
+      if (range->has_stepper_d)
+        {
+          layout->stepper_d.width = stepper_width;
+          layout->stepper_d.height = stepper_height;
+        }
+      else
+        {
+          layout->stepper_d.width = 0;
+          layout->stepper_d.height = 0;
+        }
+      
+      layout->stepper_d.x = layout->stepper_a.x;
+      layout->stepper_d.y = range_rect.y + range_rect.height - layout->stepper_d.height - trough_border;
 
-  gdk_window_get_size (range->trough, &trough_width, NULL);
-  gdk_window_get_size (range->slider, &slider_length, NULL);
+      /* Stepper C */
 
-  _gtk_range_get_props (range, NULL, &trough_border, NULL, &stepper_spacing);
-   
-  tleft = trough_border;
-  tright = trough_width - slider_length - trough_border;
+      if (range->has_stepper_c)
+        {
+          layout->stepper_c.width = stepper_width;
+          layout->stepper_c.height = stepper_height;
+        }
+      else
+        {
+          layout->stepper_c.width = 0;
+          layout->stepper_c.height = 0;
+        }
+      
+      layout->stepper_c.x = layout->stepper_a.x;
+      layout->stepper_c.y = layout->stepper_d.y - layout->stepper_c.height;
 
-  if (range->step_back)
+      /* Now the trough is the remaining space between steppers B and C,
+       * if any
+       */
+      layout->trough.x = range_rect.x;
+      layout->trough.y = layout->stepper_b.y + layout->stepper_b.height;
+      layout->trough.width = range_rect.width;
+      layout->trough.height = layout->stepper_c.y - (layout->stepper_b.y + layout->stepper_b.height);
+      
+      /* Slider fits into the trough, with stepper_spacing on either side,
+       * and the size/position based on the adjustment or fixed, depending.
+       */
+      layout->slider.x = layout->trough.x + trough_border;
+      layout->slider.width = layout->trough.width - trough_border * 2;
+
+      /* Compute slider position/length */
+      {
+        gint y, bottom, top, height;
+        
+        top = layout->trough.y + stepper_spacing;
+        bottom = layout->trough.y + layout->trough.height - stepper_spacing;
+        
+        /* slider height is the fraction (page_size /
+         * total_adjustment_range) times the trough height in pixels
+         */
+        height = ((bottom - top) * (range->adjustment->page_size /
+                                    (range->adjustment->upper - range->adjustment->lower)));
+        
+        if (height < range->min_slider_size ||
+            range->slider_size_fixed)
+          height = range->min_slider_size;
+        
+        height = MIN (height, (layout->trough.height - stepper_spacing * 2));
+        
+        y = top;
+        
+        y += (bottom - top - height) * ((range->adjustment->value - range->adjustment->lower) /
+                                        (range->adjustment->upper - range->adjustment->lower - range->adjustment->page_size));
+        
+        y = CLAMP (y, top, bottom);
+        
+        if (should_invert (range))
+          y = bottom - (y - top + height);
+        
+        layout->slider.y = y;
+        layout->slider.height = height;
+
+        /* These are publically exported */
+        range->slider_start = layout->slider.y;
+        range->slider_end = layout->slider.y + layout->slider.height;
+      }
+    }
+  else
     {
-      gdk_window_get_size (range->step_back, &tmp_width, NULL);
-      tleft += (tmp_width + stepper_spacing);
+      gint stepper_width, stepper_height;
+
+      /* Steppers are the height of the range, and stepper_size in
+       * width, or if we don't have enough width, divided equally
+       * among available space.
+       */
+      stepper_height = range_rect.height - trough_border * 2;
+
+      if (stepper_height < 1)
+        stepper_height = range_rect.height; /* screw the trough border */
+
+      if (n_steppers == 0)
+        stepper_width = 0; /* avoid divide by n_steppers */
+      else
+        stepper_width = MIN (stepper_size, (range_rect.width / n_steppers));
+
+      /* Stepper A */
+      
+      layout->stepper_a.x = range_rect.x + trough_border;
+      layout->stepper_a.y = range_rect.y + trough_border;
+
+      if (range->has_stepper_a)
+        {
+          layout->stepper_a.width = stepper_width;
+          layout->stepper_a.height = stepper_height;
+        }
+      else
+        {
+          layout->stepper_a.width = 0;
+          layout->stepper_a.height = 0;
+        }
+
+      /* Stepper B */
+      
+      layout->stepper_b.x = layout->stepper_a.x + layout->stepper_a.width;
+      layout->stepper_b.y = layout->stepper_a.y;
+
+      if (range->has_stepper_b)
+        {
+          layout->stepper_b.width = stepper_width;
+          layout->stepper_b.height = stepper_height;
+        }
+      else
+        {
+          layout->stepper_b.width = 0;
+          layout->stepper_b.height = 0;
+        }
+
+      /* Stepper D */
+
+      if (range->has_stepper_d)
+        {
+          layout->stepper_d.width = stepper_width;
+          layout->stepper_d.height = stepper_height;
+        }
+      else
+        {
+          layout->stepper_d.width = 0;
+          layout->stepper_d.height = 0;
+        }
+
+      layout->stepper_d.x = range_rect.x + range_rect.width - layout->stepper_d.width - trough_border;
+      layout->stepper_d.y = layout->stepper_a.y;
+
+
+      /* Stepper C */
+
+      if (range->has_stepper_c)
+        {
+          layout->stepper_c.width = stepper_width;
+          layout->stepper_c.height = stepper_height;
+        }
+      else
+        {
+          layout->stepper_c.width = 0;
+          layout->stepper_c.height = 0;
+        }
+      
+      layout->stepper_c.x = layout->stepper_d.x - layout->stepper_c.width;
+      layout->stepper_c.y = layout->stepper_a.y;
+
+      /* Now the trough is the remaining space between steppers B and C,
+       * if any
+       */
+      layout->trough.x = layout->stepper_b.x + layout->stepper_b.width;
+      layout->trough.y = range_rect.y;
+
+      layout->trough.width = layout->stepper_c.x - (layout->stepper_b.x + layout->stepper_b.width);
+      layout->trough.height = range_rect.height;
+      
+      /* Slider fits into the trough, with stepper_spacing on either side,
+       * and the size/position based on the adjustment or fixed, depending.
+       */
+      layout->slider.y = layout->trough.y + trough_border;
+      layout->slider.height = layout->trough.height - trough_border * 2;
+
+      /* Compute slider position/length */
+      {
+        gint x, left, right, width;
+        
+        left = layout->trough.x + stepper_spacing;
+        right = layout->trough.x + layout->trough.width - stepper_spacing;
+        
+        /* slider width is the fraction (page_size /
+         * total_adjustment_range) times the trough width in pixels
+         */
+        width = ((right - left) * (range->adjustment->page_size /
+                                   (range->adjustment->upper - range->adjustment->lower)));
+        
+        if (width < range->min_slider_size ||
+            range->slider_size_fixed)
+          width = range->min_slider_size;
+        
+        width = MIN (width, (layout->trough.width - stepper_spacing * 2));
+        
+        x = left;
+        
+        x += (right - left - width) * ((range->adjustment->value - range->adjustment->lower) /
+                                       (range->adjustment->upper - range->adjustment->lower - range->adjustment->page_size));
+        
+        x = CLAMP (x, left, right);
+        
+        if (should_invert (range))
+          x = right - (x - left + width);
+        
+        layout->slider.x = x;
+        layout->slider.width = width;
+
+        /* These are publically exported */
+        range->slider_start = layout->slider.x;
+        range->slider_end = layout->slider.x + layout->slider.width;
+      }
     }
+  
+  gtk_range_update_mouse_location (range);
+}
 
-  if (range->step_forw)
+static GdkRectangle*
+get_area (GtkRange     *range,
+          MouseLocation location)
+{
+  switch (location)
     {
-      gdk_window_get_size (range->step_forw, &tmp_width, NULL);
-      tright -= (tmp_width + stepper_spacing);
+    case MOUSE_STEPPER_A:
+      return &range->layout->stepper_a;
+    case MOUSE_STEPPER_B:
+      return &range->layout->stepper_b;
+    case MOUSE_STEPPER_C:
+      return &range->layout->stepper_c;
+    case MOUSE_STEPPER_D:
+      return &range->layout->stepper_d;
+    case MOUSE_TROUGH:
+      return &range->layout->trough;
+    case MOUSE_SLIDER:
+      return &range->layout->slider;
+    case MOUSE_WIDGET:
+    case MOUSE_OUTSIDE:
+      break;
     }
 
-  if (left)
-    *left = tleft;
-  if (right)
-    *right = tright;
+  g_warning (G_STRLOC": bug");
+  return NULL;
 }
 
 static void
-gtk_range_trough_vdims (GtkRange *range,
-                       gint     *top,
-                       gint     *bottom)
+gtk_range_internal_set_value (GtkRange *range,
+                              gdouble   value)
 {
-  gint trough_height;
-  gint slider_length;
-  gint tmp_height;
-  gint ttop;
-  gint tbottom;
-  gint stepper_spacing;
-  gint trough_border;
+  value = CLAMP (value, range->adjustment->lower,
+                 (range->adjustment->upper - range->adjustment->page_size));
 
-  g_return_if_fail (range != NULL);
-
-  _gtk_range_get_props (range, NULL, &trough_border, NULL, &stepper_spacing);
-   
-  gdk_window_get_size (range->trough, NULL, &trough_height);
-  gdk_window_get_size (range->slider, NULL, &slider_length);
-
-  ttop = trough_border;
-  tbottom = trough_height - slider_length - trough_border;
+  if (range->round_digits >= 0)
+    {
+      char buffer[128];
 
-  if (range->step_back)
+      /* This is just so darn lame. */
+      g_snprintf (buffer, 128, "%0.*f",
+                  range->round_digits, value);
+      sscanf (buffer, "%lf", &value);
+    }
+  
+  if (range->adjustment->value != value)
     {
-      gdk_window_get_size (range->step_back, NULL, &tmp_height);
-      ttop += (tmp_height + stepper_spacing);
+      range->need_recalc = TRUE;
+
+      gtk_widget_queue_draw (GTK_WIDGET (range));
+      
+      switch (range->update_policy)
+        {
+        case GTK_UPDATE_CONTINUOUS:
+          gtk_adjustment_set_value (range->adjustment, value);
+          break;
+
+          /* Delayed means we update after a period of inactivity */
+        case GTK_UPDATE_DELAYED:
+          gtk_range_reset_update_timer (range);
+          /* FALL THRU */
+
+          /* Discontinuous means we update on button release */
+        case GTK_UPDATE_DISCONTINUOUS:
+          /* don't emit value_changed signal */
+          range->adjustment->value = value;
+          range->update_pending = TRUE;
+          break;
+        }
     }
+}
 
-  if (range->step_forw)
+static void
+gtk_range_update_value (GtkRange *range)
+{
+  gtk_range_remove_update_timer (range);
+  
+  if (range->update_pending)
     {
-      gdk_window_get_size (range->step_forw, NULL, &tmp_height);
-      tbottom -= (tmp_height + stepper_spacing);
+      gtk_adjustment_value_changed (range->adjustment);
+
+      range->update_pending = FALSE;
     }
+}
+
+struct _GtkRangeStepTimer
+{
+  guint timeout_id;
+  GtkScrollType step;
+};
+
+static gboolean
+second_timeout (gpointer data)
+{
+  GtkRange *range;
+
+  range = GTK_RANGE (data);
 
-  if (top)
-    *top = ttop;
-  if (bottom)
-    *bottom = tbottom;
+  gtk_range_scroll (range, range->timer->step);
+  
+  return TRUE;
 }
 
-static void
-gtk_range_style_set (GtkWidget *widget,
-                     GtkStyle  *previous_style)
+static gboolean
+initial_timeout (gpointer data)
 {
   GtkRange *range;
 
-  g_return_if_fail (widget != NULL);
-  g_return_if_fail (GTK_IS_RANGE (widget));
+  range = GTK_RANGE (data);
 
-  range = GTK_RANGE (widget);
+  range->timer->timeout_id = 
+    g_timeout_add (SCROLL_LATER_DELAY,
+                   second_timeout,
+                   range);
 
-  if (GTK_WIDGET_REALIZED (widget))
-    {
-      if (range->trough)
-       gtk_style_set_background (widget->style, range->trough, GTK_STATE_ACTIVE);
+  /* remove self */
+  return FALSE;
+}
 
-      if (range->slider)
-       gtk_style_set_background (widget->style, range->slider, GTK_STATE_NORMAL);
-      
-      /* The backgrounds of the step_forw and step_back never actually
-       * get drawn in draw calls, so we call gdk_window_clear() here
-       * so they get the correct colors. This is a hack. OWT.
-       */
+static void
+gtk_range_add_step_timer (GtkRange      *range,
+                          GtkScrollType  step)
+{
+  g_return_if_fail (range->timer == NULL);
+  g_return_if_fail (step != GTK_SCROLL_NONE);
+  
+  range->timer = g_new (GtkRangeStepTimer, 1);
 
-      if (range->step_forw)
-       {
-         gtk_style_set_background (widget->style, range->step_forw, GTK_STATE_ACTIVE);
-         gdk_window_clear (range->step_forw);
-       }
+  range->timer->timeout_id =
+    g_timeout_add (SCROLL_INITIAL_DELAY,
+                   initial_timeout,
+                   range);
+  range->timer->step = step;
+}
 
-      if (range->step_back)
-       {
-         gtk_style_set_background (widget->style, range->step_back, GTK_STATE_ACTIVE);
-         gdk_window_clear (range->step_back);
-       }
+static void
+gtk_range_remove_step_timer (GtkRange *range)
+{
+  if (range->timer)
+    {
+      if (range->timer->timeout_id != 0)
+        g_source_remove (range->timer->timeout_id);
+
+      g_free (range->timer);
+
+      range->timer = NULL;
     }
 }
 
-void
-_gtk_range_get_props (GtkRange *range,
-                     gint     *slider_width,
-                     gint     *trough_border,
-                     gint     *stepper_size,
-                     gint     *stepper_spacing)
+static gboolean
+update_timeout (gpointer data)
 {
-  GtkWidget *widget =  GTK_WIDGET (range);
-  
+  GtkRange *range;
 
-  if (slider_width)
-    gtk_widget_style_get (widget, "slider_width", slider_width, NULL);
-  
-  if (trough_border)
-    gtk_widget_style_get (widget, "trough_border", trough_border, NULL);
+  range = GTK_RANGE (data);
 
-  if (stepper_size)
-    gtk_widget_style_get (widget, "stepper_size", stepper_size, NULL);
+  gtk_range_update_value (range);
 
-  if (stepper_spacing)
-    gtk_widget_style_get (widget, "stepper_spacing", stepper_spacing, NULL);
+  range->update_timeout_id = 0;
+
+  /* self-remove */
+  return FALSE;
 }
 
+static void
+gtk_range_reset_update_timer (GtkRange *range)
+{
+  gtk_range_remove_update_timer (range);
+
+  range->update_timeout_id = g_timeout_add (UPDATE_DELAY,
+                                            update_timeout,
+                                            range);
+}
+
+static void
+gtk_range_remove_update_timer (GtkRange *range)
+{
+  if (range->update_timeout_id != 0)
+    {
+      g_source_remove (range->update_timeout_id);
+      range->update_timeout_id = 0;
+    }
+}
index 58fb89a38663282f0f97b678ae70255f6ff0467f..6228b74e3bde4f72465fd4e3f0c93b07e3a2eafd 100644 (file)
@@ -45,6 +45,9 @@ extern "C" {
 #define GTK_IS_RANGE_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GTK_TYPE_RANGE))
 #define GTK_RANGE_GET_CLASS(obj)  (GTK_CHECK_GET_CLASS ((obj), GTK_TYPE_RANGE, GtkRangeClass))
 
+/* These two are private/opaque types, ignore */
+typedef struct _GtkRangeLayout    GtkRangeLayout;
+typedef struct _GtkRangeStepTimer GtkRangeStepTimer;
 
 typedef struct _GtkRange        GtkRange;
 typedef struct _GtkRangeClass   GtkRangeClass;
@@ -53,116 +56,80 @@ struct _GtkRange
 {
   GtkWidget widget;
 
-  GdkWindow *trough;
-  GdkWindow *slider;
-  GdkWindow *step_forw;
-  GdkWindow *step_back;
-
-  gint16 x_click_point;
-  gint16 y_click_point;
-
-  guint8 button;
-  gint8 digits;
-  guint policy : 2;
-  guint scroll_type : 5;
-  guint in_child : 3;
-  guint click_child : 3;
-  guint need_timer : 1;
-  guint flippable : 1;
+  GtkAdjustment *adjustment;
+  GtkUpdateType update_policy;
   guint inverted : 1;
+
+  /*< protected >*/
+  
+  guint flippable : 1;
   
-  guint32 timer;
+  /* Steppers are: < > ---- < >
+   *               a b      c d
+   */
+   
+  guint has_stepper_a : 1;
+  guint has_stepper_b : 1;
+  guint has_stepper_c : 1;
+  guint has_stepper_d : 1;
+
+  guint need_recalc : 1;
+
+  guint slider_size_fixed : 1;
+  
+  gint min_slider_size;
 
-  gdouble old_value;
-  gdouble old_lower;
-  gdouble old_upper;
-  gdouble old_page_size;
+  GtkOrientation orientation;
 
-  GtkAdjustment *adjustment;
+  /* Area of entire stepper + trough assembly in widget->window coords */
+  GdkRectangle range_rect;
+  /* Slider range along the long dimension, in widget->window coords */
+  gint slider_start, slider_end;
+
+  /* Round off value to this many digits, -1 for no rounding */
+  gint round_digits;
+  
+  /*< private >*/
+  guint trough_click_forward : 1;  /* trough click was on the forward side of slider */
+  guint update_pending : 1;        /* need to emit value_changed */
+  GtkRangeLayout *layout;
+  GtkRangeStepTimer *timer;
+  gint slide_initial_slider_position;
+  gint slide_initial_coordinate;
+  guint update_timeout_id;
 };
 
 struct _GtkRangeClass
 {
   GtkWidgetClass parent_class;
 
-  gint min_slider_size;
-
-  guint8 trough;
-  guint8 slider;
-  guint8 step_forw;
-  guint8 step_back;
+  /* what detail to pass to GTK drawing functions */
+  gchar *slider_detail;
+  gchar *stepper_detail;
   
   /* action signals for keybindings */
   void (* move_slider)      (GtkRange     *range,
-                             GtkScrollType scroll,
-                             GtkTroughType trough);
-
-  /* Completely broken virtual functions, please ignore */
-
-  void (* draw_background)  (GtkRange *range);
-  void (* clear_background) (GtkRange *range);
-  void (* draw_trough)      (GtkRange *range);
-  void (* draw_slider)      (GtkRange *range);
-  void (* draw_step_forw)   (GtkRange *range);
-  void (* draw_step_back)   (GtkRange *range);
-  void (* slider_update)    (GtkRange *range);
-  gboolean (* trough_click) (GtkRange *range,
-                            gint      x,
-                            gint      y,
-                            gdouble  *jump_perc);
-  void (* motion)           (GtkRange *range,
-                            gint      xdelta,
-                            gint      ydelta);
-  gboolean (* timer)        (GtkRange *range);
+                             GtkScrollType scroll);
+
+  /* Virtual functions */
+  void (* get_range_border) (GtkRange     *range,
+                             GtkBorder    *border);
 };
 
 
 GtkType        gtk_range_get_type               (void) G_GNUC_CONST;
-GtkAdjustment* gtk_range_get_adjustment         (GtkRange      *range);
+
 void           gtk_range_set_update_policy      (GtkRange      *range,
                                                 GtkUpdateType  policy);
+
 void           gtk_range_set_adjustment         (GtkRange      *range,
                                                 GtkAdjustment *adjustment);
+GtkAdjustment* gtk_range_get_adjustment         (GtkRange      *range);
 
 void           gtk_range_set_inverted           (GtkRange      *range,
                                                  gboolean       setting);
 gboolean       gtk_range_get_inverted           (GtkRange      *range);
 
-void           _gtk_range_draw_background        (GtkRange      *range);
-void           _gtk_range_clear_background       (GtkRange      *range);
-void           _gtk_range_draw_trough            (GtkRange      *range);
-void           _gtk_range_draw_slider            (GtkRange      *range);
-void           _gtk_range_draw_step_forw         (GtkRange      *range);
-void           _gtk_range_draw_step_back         (GtkRange      *range);
-void           _gtk_range_slider_update          (GtkRange      *range);
-gboolean       _gtk_range_trough_click           (GtkRange      *range,
-                                                  gint           x,
-                                                  gint           y,
-                                                  gdouble       *jump_perc);
-
-void           _gtk_range_default_hslider_update (GtkRange      *range);
-void           _gtk_range_default_vslider_update (GtkRange      *range);
-gboolean       _gtk_range_default_htrough_click  (GtkRange      *range,
-                                                  gint           x,
-                                                  gint           y,
-                                                  gdouble       *jump_perc);
-gboolean       _gtk_range_default_vtrough_click  (GtkRange      *range,
-                                                  gint           x,
-                                                  gint           y,
-                                                  gdouble       *jump_perc);
-void           _gtk_range_default_hmotion        (GtkRange      *range,
-                                                  gint           xdelta,
-                                                  gint           ydelta);
-void           _gtk_range_default_vmotion        (GtkRange      *range,
-                                                  gint           xdelta,
-                                                  gint           ydelta);
-
-void _gtk_range_get_props (GtkRange *range,
-                          gint     *slider_width,
-                          gint     *trough_border,
-                          gint     *stepper_size,
-                          gint     *stepper_spacing);
-
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
index de5c180bc7b19e99171b328e47d6262fcbed8784..f51d7d4fe1832bbbfc336249acd1617515d90c3e 100644 (file)
@@ -1,5 +1,6 @@
 /* GTK - The GIMP Toolkit
  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ * Copyright (C) 2001 Red Hat, Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -28,6 +29,8 @@
 #include "gtkintl.h"
 #include "gtkscale.h"
 #include "gtkmarshal.h"
+#include "gdk/gdkkeysyms.h"
+#include "gtkbindings.h"
 
 enum {
   PROP_0,
@@ -42,25 +45,22 @@ enum {
 };
 
 static guint signals[LAST_SIGNAL];
-
-static void gtk_scale_class_init   (GtkScaleClass *klass);
-static void gtk_scale_init         (GtkScale      *scale);
-static void gtk_scale_set_property (GObject       *object,
-                                   guint          prop_id,
-                                   const GValue  *value,
-                                   GParamSpec    *pspec);
-static void gtk_scale_get_property (GObject       *object,
-                                   guint          prop_id,
-                                   GValue        *value,
-                                   GParamSpec    *pspec);
-static void gtk_scale_map          (GtkWidget     *widget);
-static void gtk_scale_unmap        (GtkWidget     *widget);
-
-static void gtk_scale_draw_background (GtkRange      *range);
-
-
 static GtkRangeClass *parent_class = NULL;
 
+static void gtk_scale_class_init       (GtkScaleClass *klass);
+static void gtk_scale_init             (GtkScale      *scale);
+static void gtk_scale_set_property     (GObject       *object,
+                                        guint          prop_id,
+                                        const GValue  *value,
+                                        GParamSpec    *pspec);
+static void gtk_scale_get_property     (GObject       *object,
+                                        guint          prop_id,
+                                        GValue        *value,
+                                        GParamSpec    *pspec);
+static void gtk_scale_style_set        (GtkWidget     *widget,
+                                        GtkStyle      *previous);
+static void gtk_scale_get_range_border (GtkRange      *range,
+                                        GtkBorder     *border);
 
 GtkType
 gtk_scale_get_type (void)
@@ -103,6 +103,12 @@ single_string_accumulator (GSignalInvocationHint *ihint,
   return continue_emission;
 }
 
+
+#define add_slider_binding(binding_set, keyval, mask, scroll)          \
+  gtk_binding_entry_add_signal (binding_set, keyval, mask,             \
+                                "move_slider", 1,                      \
+                                GTK_TYPE_SCROLL_TYPE, scroll)
+
 static void
 gtk_scale_class_init (GtkScaleClass *class)
 {
@@ -110,7 +116,8 @@ gtk_scale_class_init (GtkScaleClass *class)
   GtkObjectClass *object_class;
   GtkWidgetClass *widget_class;
   GtkRangeClass *range_class;
-
+  GtkBindingSet *binding_set;
+  
   gobject_class = G_OBJECT_CLASS (class);
   object_class = (GtkObjectClass*) class;
   range_class = (GtkRangeClass*) class;
@@ -121,11 +128,10 @@ gtk_scale_class_init (GtkScaleClass *class)
   gobject_class->set_property = gtk_scale_set_property;
   gobject_class->get_property = gtk_scale_get_property;
 
-  widget_class->map = gtk_scale_map;
-  widget_class->unmap = gtk_scale_unmap;
-  
-  range_class->draw_background = gtk_scale_draw_background;
+  widget_class->style_set = gtk_scale_style_set;
 
+  range_class->get_range_border = gtk_scale_get_range_border;
+  
   signals[FORMAT_VALUE] =
     g_signal_newc ("format_value",
                   G_TYPE_FROM_CLASS (object_class),
@@ -171,8 +177,99 @@ gtk_scale_class_init (GtkScaleClass *class)
                                                             G_MAXINT,
                                                             31,
                                                             G_PARAM_READABLE));
-  class->value_spacing = 2;
-  class->draw_value = NULL;
+
+  gtk_widget_class_install_style_property (widget_class,
+                                          g_param_spec_int ("value_spacing",
+                                                            _("Value spacing"),
+                                                            _("Space between value text and the slider/trough area"),
+                                                            0,
+                                                            G_MAXINT,
+                                                            2,
+                                                            G_PARAM_READABLE));
+  
+  /* All bindings (even arrow keys) are on both h/v scale, because
+   * blind users etc. don't care about scale orientation.
+   */
+  
+  binding_set = gtk_binding_set_by_class (class);
+
+  add_slider_binding (binding_set, GDK_Left, 0,
+                      GTK_SCROLL_STEP_LEFT);
+
+  add_slider_binding (binding_set, GDK_Left, GDK_CONTROL_MASK,
+                      GTK_SCROLL_PAGE_LEFT);
+
+  add_slider_binding (binding_set, GDK_KP_Left, 0,
+                      GTK_SCROLL_STEP_LEFT);
+
+  add_slider_binding (binding_set, GDK_KP_Left, GDK_CONTROL_MASK,
+                      GTK_SCROLL_PAGE_LEFT);
+
+
+  add_slider_binding (binding_set, GDK_Right, 0,
+                      GTK_SCROLL_STEP_RIGHT);
+
+  add_slider_binding (binding_set, GDK_Right, GDK_CONTROL_MASK,
+                      GTK_SCROLL_PAGE_RIGHT);
+
+  add_slider_binding (binding_set, GDK_KP_Right, 0,
+                      GTK_SCROLL_STEP_RIGHT);
+
+  add_slider_binding (binding_set, GDK_KP_Right, GDK_CONTROL_MASK,
+                      GTK_SCROLL_PAGE_RIGHT);
+
+  add_slider_binding (binding_set, GDK_Up, 0,
+                      GTK_SCROLL_STEP_UP);
+
+  add_slider_binding (binding_set, GDK_Up, GDK_CONTROL_MASK,
+                      GTK_SCROLL_PAGE_UP);
+
+  add_slider_binding (binding_set, GDK_KP_Up, 0,
+                      GTK_SCROLL_STEP_UP);
+
+  add_slider_binding (binding_set, GDK_KP_Up, GDK_CONTROL_MASK,
+                      GTK_SCROLL_PAGE_UP);
+
+
+  add_slider_binding (binding_set, GDK_Down, 0,
+                      GTK_SCROLL_STEP_DOWN);
+
+  add_slider_binding (binding_set, GDK_Down, GDK_CONTROL_MASK,
+                      GTK_SCROLL_PAGE_DOWN);
+
+  add_slider_binding (binding_set, GDK_KP_Down, 0,
+                      GTK_SCROLL_STEP_DOWN);
+
+  add_slider_binding (binding_set, GDK_KP_Down, GDK_CONTROL_MASK,
+                      GTK_SCROLL_PAGE_DOWN);
+
+  /* I think most users will find it strange that these move
+   * logically instead of visually...
+   */
+   
+  add_slider_binding (binding_set, GDK_Page_Up, 0,
+                      GTK_SCROLL_PAGE_BACKWARD);
+
+  add_slider_binding (binding_set, GDK_KP_Page_Up, 0,
+                      GTK_SCROLL_PAGE_BACKWARD);  
+
+  add_slider_binding (binding_set, GDK_Page_Down, 0,
+                      GTK_SCROLL_PAGE_FORWARD);
+
+  add_slider_binding (binding_set, GDK_KP_Page_Down, 0,
+                      GTK_SCROLL_PAGE_FORWARD);
+
+  add_slider_binding (binding_set, GDK_Home, 0,
+                      GTK_SCROLL_START);
+
+  add_slider_binding (binding_set, GDK_KP_Home, 0,
+                      GTK_SCROLL_START);
+
+  add_slider_binding (binding_set, GDK_End, 0,
+                      GTK_SCROLL_END);
+
+  add_slider_binding (binding_set, GDK_KP_End, 0,
+                      GTK_SCROLL_END);
 }
 
 static void
@@ -215,7 +312,7 @@ gtk_scale_get_property (GObject      *object,
   switch (prop_id)
     {
     case PROP_DIGITS:
-      g_value_set_int (value, GTK_RANGE (scale)->digits);
+      g_value_set_int (value, scale->digits);
       break;
     case PROP_DRAW_VALUE:
       g_value_set_boolean (value, scale->draw_value);
@@ -231,64 +328,56 @@ gtk_scale_get_property (GObject      *object,
 
 static void
 gtk_scale_init (GtkScale *scale)
-{
-  GTK_WIDGET_SET_FLAGS (scale, GTK_CAN_FOCUS);
-  GTK_WIDGET_SET_FLAGS (scale, GTK_NO_WINDOW);
-  GTK_RANGE (scale)->digits = 1;
-  scale->draw_value = TRUE;
-  scale->value_pos = GTK_POS_TOP;
-}
-
-static void
-gtk_scale_map (GtkWidget *widget)
 {
   GtkRange *range;
 
-  g_return_if_fail (widget != NULL);
-  g_return_if_fail (GTK_IS_SCALE (widget));
-
-  GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
-  range = GTK_RANGE (widget);
-
-  gdk_window_show (range->trough);
-}
-
-static void
-gtk_scale_unmap (GtkWidget *widget)
-{
-  GtkRange *range;
-
-  g_return_if_fail (widget != NULL);
-  g_return_if_fail (GTK_IS_SCALE (widget));
-
-  GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
-  range = GTK_RANGE (widget);
-
-  if (GTK_WIDGET_NO_WINDOW (widget))
-     gtk_widget_queue_clear (widget);
+  range = GTK_RANGE (scale);
+  
+  GTK_WIDGET_SET_FLAGS (scale, GTK_CAN_FOCUS);
 
-  gdk_window_hide (range->trough);
+  range->slider_size_fixed = TRUE;
+  range->has_stepper_a = FALSE;
+  range->has_stepper_b = FALSE;
+  range->has_stepper_c = FALSE;
+  range->has_stepper_d = FALSE;
+  
+  scale->draw_value = TRUE;
+  scale->value_pos = GTK_POS_TOP;
+  scale->digits = 1;
+  range->round_digits = scale->digits;
 }
 
 void
 gtk_scale_set_digits (GtkScale *scale,
                      gint      digits)
 {
-  g_return_if_fail (scale != NULL);
+  GtkRange *range;
+  
   g_return_if_fail (GTK_IS_SCALE (scale));
 
+  range = GTK_RANGE (scale);
+  
   digits = CLAMP (digits, -1, 16);
 
-  if (GTK_RANGE (scale)->digits != digits)
+  if (scale->digits != digits)
     {
-      GTK_RANGE (scale)->digits = digits;
-
+      scale->digits = digits;
+      range->round_digits = digits;
+      
       gtk_widget_queue_resize (GTK_WIDGET (scale));
 
       g_object_notify (G_OBJECT (scale), "digits");
     }
 }
 
+gint
+gtk_scale_get_digits (GtkScale *scale)
+{
+  g_return_val_if_fail (GTK_IS_SCALE (scale), -1);
+
+  return scale->digits;
+}
+
 void
 gtk_scale_set_draw_value (GtkScale *scale,
                          gboolean  draw_value)
@@ -308,11 +397,18 @@ gtk_scale_set_draw_value (GtkScale *scale,
     }
 }
 
+gboolean
+gtk_scale_get_draw_value (GtkScale *scale)
+{
+  g_return_val_if_fail (GTK_IS_SCALE (scale), FALSE);
+
+  return scale->draw_value;
+}
+
 void
 gtk_scale_set_value_pos (GtkScale        *scale,
                         GtkPositionType  pos)
 {
-  g_return_if_fail (scale != NULL);
   g_return_if_fail (GTK_IS_SCALE (scale));
 
   if (scale->value_pos != pos)
@@ -326,10 +422,60 @@ gtk_scale_set_value_pos (GtkScale        *scale,
     }
 }
 
+GtkPositionType
+gtk_scale_get_value_pos (GtkScale *scale)
+{
+  g_return_val_if_fail (GTK_IS_SCALE (scale), 0);
+
+  return scale->value_pos;
+}
+
+static void
+gtk_scale_get_range_border (GtkRange  *range,
+                            GtkBorder *border)
+{
+  GtkWidget *widget;
+  GtkScale *scale;
+  gint w, h;
+  
+  widget = GTK_WIDGET (range);
+  scale = GTK_SCALE (range);
+
+  _gtk_scale_get_value_size (scale, &w, &h);
+
+  border->left = 0;
+  border->right = 0;
+  border->top = 0;
+  border->bottom = 0;
+
+  if (scale->draw_value)
+    {
+      gint value_spacing;
+      gtk_widget_style_get (widget, "value_spacing", &value_spacing, NULL);
+
+      switch (scale->value_pos)
+        {
+        case GTK_POS_LEFT:
+          border->left += w + value_spacing;
+          break;
+        case GTK_POS_RIGHT:
+          border->right += w + value_spacing;
+          break;
+        case GTK_POS_TOP:
+          border->top += h + value_spacing;
+          break;
+        case GTK_POS_BOTTOM:
+          border->bottom += h + value_spacing;
+          break;
+        }
+    }
+}
+
+/* FIXME this could actually be static at the moment. */
 void
-gtk_scale_get_value_size (GtkScale *scale,
-                         gint     *width,
-                         gint     *height)
+_gtk_scale_get_value_size (GtkScale *scale,
+                           gint     *width,
+                           gint     *height)
 {
   GtkRange *range;
 
@@ -380,39 +526,25 @@ gtk_scale_get_value_size (GtkScale *scale,
 
 }
 
-gint
-gtk_scale_get_value_width (GtkScale *scale)
+static void
+gtk_scale_style_set (GtkWidget *widget,
+                     GtkStyle  *previous)
 {
-  gint width;
+  gint slider_length;
+  GtkRange *range;
 
-  g_return_val_if_fail (scale != NULL, 0);
-  g_return_val_if_fail (GTK_IS_SCALE (scale), 0);
+  range = GTK_RANGE (widget);
   
-  gtk_scale_get_value_size (scale, &width, NULL);
-
-  return width;
-}
-
-void
-gtk_scale_draw_value (GtkScale *scale)
-{
-  g_return_if_fail (scale != NULL);
-  g_return_if_fail (GTK_IS_SCALE (scale));
-
-  if (GTK_SCALE_GET_CLASS (scale)->draw_value)
-    GTK_SCALE_GET_CLASS (scale)->draw_value (scale);
+  gtk_widget_style_get (widget,
+                        "slider_length", &slider_length,
+                        NULL);
+  
+  range->min_slider_size = slider_length;
+  
+  (* GTK_WIDGET_CLASS (parent_class)->style_set) (widget, previous);
 }
 
 
-static void
-gtk_scale_draw_background (GtkRange *range)
-{
-  g_return_if_fail (range != NULL);
-  g_return_if_fail (GTK_IS_SCALE (range));
-
-  gtk_scale_draw_value (GTK_SCALE (range));
-}
-
 /**
  * _gtk_scale_format_value:
  * @scale: a #GtkScale
@@ -438,6 +570,6 @@ _gtk_scale_format_value (GtkScale *scale,
   if (fmt)
     return fmt;
   else
-    return g_strdup_printf ("%0.*f", GTK_RANGE (scale)->digits,
+    return g_strdup_printf ("%0.*f", scale->digits,
                             value);
 }
index b6cd71954701823b6badcf57cc2c474a9ce62f30..bfb099ef1ba12165dafc71cf1fa3ef8fddb170a9 100644 (file)
@@ -52,6 +52,7 @@ struct _GtkScale
 {
   GtkRange range;
 
+  gint digits;
   guint draw_value : 1;
   guint value_pos : 2;
 };
@@ -60,8 +61,6 @@ struct _GtkScaleClass
 {
   GtkRangeClass parent_class;
 
-  gint value_spacing;
-
   gchar* (* format_value) (GtkRange *range,
                            gdouble   value);  
   
@@ -69,19 +68,21 @@ struct _GtkScaleClass
 };
 
 GtkType gtk_scale_get_type        (void) G_GNUC_CONST;
-void    gtk_scale_set_digits      (GtkScale        *scale,
-                                  gint             digits);
-void    gtk_scale_set_draw_value  (GtkScale        *scale,
-                                  gboolean         draw_value);
-void    gtk_scale_set_value_pos   (GtkScale        *scale,
-                                  GtkPositionType  pos);
-gint    gtk_scale_get_value_width (GtkScale        *scale);
-void    gtk_scale_get_value_size  (GtkScale        *scale,
-                                  gint            *width,
-                                  gint            *height);
-
-void    gtk_scale_draw_value      (GtkScale        *scale);
 
+void            gtk_scale_set_digits     (GtkScale        *scale,
+                                          gint             digits);
+gint            gtk_scale_get_digits     (GtkScale        *scale);
+void            gtk_scale_set_draw_value (GtkScale        *scale,
+                                          gboolean         draw_value);
+gboolean        gtk_scale_get_draw_value (GtkScale        *scale);
+void            gtk_scale_set_value_pos  (GtkScale        *scale,
+                                          GtkPositionType  pos);
+GtkPositionType gtk_scale_get_value_pos  (GtkScale        *scale);
+
+
+void    _gtk_scale_get_value_size  (GtkScale        *scale,
+                                    gint            *width,
+                                    gint            *height);
 gchar  *_gtk_scale_format_value   (GtkScale        *scale,
                                    gdouble          value);
 
index c62fc13c2e11ff6c2773c9f17bdb4198ae706280..28e7ff694dae52d3383cdb65d2c24911a16f7d99 100644 (file)
@@ -1,5 +1,6 @@
 /* GTK - The GIMP Toolkit
  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ * Copyright (C) 2001 Red Hat, Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  */
 
 #include "gtkscrollbar.h"
+#include "gtkintl.h"
 
 static void gtk_scrollbar_class_init (GtkScrollbarClass *klass);
 static void gtk_scrollbar_init       (GtkScrollbar      *scrollbar);
+static void gtk_scrollbar_style_set  (GtkWidget         *widget,
+                                      GtkStyle          *previous);
+
+static gpointer parent_class;
 
 GtkType
 gtk_scrollbar_get_type (void)
@@ -57,9 +63,101 @@ gtk_scrollbar_get_type (void)
 static void
 gtk_scrollbar_class_init (GtkScrollbarClass *class)
 {
+  GtkWidgetClass *widget_class;
+
+  widget_class = GTK_WIDGET_CLASS (class);
+
+  parent_class = g_type_class_peek_parent (class);
+  
+  widget_class->style_set = gtk_scrollbar_style_set;
+  
+  gtk_widget_class_install_style_property (widget_class,
+                                          g_param_spec_int ("min_slider_length",
+                                                            _("Minimum Slider Length"),
+                                                            _("Minimum length of scrollbar slider"),
+                                                            0,
+                                                            G_MAXINT,
+                                                            7,
+                                                            G_PARAM_READABLE));
+
+  gtk_widget_class_install_style_property (widget_class,
+                                          g_param_spec_boolean ("fixed_slider_length",
+                                                                 _("Fixed slider size"),
+                                                                 _("Don't change slider size, just lock it to the minimum length"),
+                                                                 FALSE,
+                                                                 
+                                                                 G_PARAM_READABLE));
+  
+  gtk_widget_class_install_style_property (widget_class,
+                                          g_param_spec_boolean ("has_backward_stepper",
+                                                                 _("Backward stepper"),
+                                                                 _("Display the standard backward arrow button"),
+                                                                 TRUE,
+                                                                 
+                                                                 G_PARAM_READABLE));
+
+    gtk_widget_class_install_style_property (widget_class,
+                                             g_param_spec_boolean ("has_forward_stepper",
+                                                                   _("Forward stepper"),
+                                                                   _("Display the standard forward arrow button"),
+                                                                   TRUE,
+                                                                   
+                                                                   G_PARAM_READABLE));
+
+  gtk_widget_class_install_style_property (widget_class,
+                                          g_param_spec_boolean ("has_secondary_backward_stepper",
+                                                                 _("Secondary backward stepper"),
+                                                                 _("Display a second backward arrow button on the opposite end of the scrollbar"),
+                                                                 FALSE,
+                                                                 
+                                                                 G_PARAM_READABLE));
+
+    gtk_widget_class_install_style_property (widget_class,
+                                             g_param_spec_boolean ("has_secondary_forward_stepper",
+                                                                   _("Secondary forward stepper"),
+                                                                   _("Display a secondary forward arrow button on the opposite end of the scrollbar"),
+                                                                   FALSE,
+                                                                   
+                                                                   G_PARAM_READABLE));
 }
 
 static void
 gtk_scrollbar_init (GtkScrollbar *scrollbar)
 {
+  GtkRange *range;
+
+  range = GTK_RANGE (scrollbar);
+}
+
+static void
+gtk_scrollbar_style_set  (GtkWidget *widget,
+                          GtkStyle  *previous)
+{
+  gint slider_length;
+  gboolean fixed_size;
+  gboolean has_a, has_b, has_c, has_d;
+  GtkRange *range;
+
+  range = GTK_RANGE (widget);
+  
+  gtk_widget_style_get (widget,
+                        "min_slider_length", &slider_length,
+                        "fixed_slider_length", &fixed_size,
+                        "has_backward_stepper", &has_a,
+                        "has_secondary_forward_stepper", &has_b,
+                        "has_secondary_backward_stepper", &has_c,
+                        "has_forward_stepper", &has_d,
+                        NULL);
+  
+  range->min_slider_size = slider_length;
+  range->slider_size_fixed = fixed_size;
+
+  range->has_stepper_a = has_a;
+  range->has_stepper_b = has_b;
+  range->has_stepper_c = has_c;
+  range->has_stepper_d = has_d;
+  
+  (* GTK_WIDGET_CLASS (parent_class)->style_set) (widget, previous);
 }
+
+
index d65355b0e44e288fa55da8dc5704f5550134a758..6aaf3305493d1ba219ba5f13376aef8dd5498737 100644 (file)
@@ -3754,14 +3754,19 @@ gtk_default_draw_slider (GtkStyle      *style,
   gtk_paint_box (style, window, state_type, shadow_type,
                  area, widget, detail, x, y, width, height);
 
-  if (orientation == GTK_ORIENTATION_HORIZONTAL)
-    gtk_paint_vline (style, window, state_type, area, widget, detail, 
-                     style->ythickness, 
-                     height - style->ythickness - 1, width / 2);
-  else
-    gtk_paint_hline (style, window, state_type, area, widget, detail, 
-                     style->xthickness, 
-                     width - style->xthickness - 1, height / 2);
+  if (detail &&
+      (strcmp ("hscale", detail) == 0 ||
+       strcmp ("vscale", detail) == 0))
+    {
+      if (orientation == GTK_ORIENTATION_HORIZONTAL)
+        gtk_paint_vline (style, window, state_type, area, widget, detail, 
+                         y + style->ythickness, 
+                         y + height - style->ythickness - 1, x + width / 2);
+      else
+        gtk_paint_hline (style, window, state_type, area, widget, detail, 
+                         x + style->xthickness, 
+                         x + width - style->xthickness - 1, y + height / 2);
+    }
 }
 
 static void
index d233e985e02dee160e4bc9b9056ea0acd71d9008..9a60d5ad845f2f4a00d754cca9be1123fcce54e1 100644 (file)
@@ -1,5 +1,5 @@
 /* GTK - The GIMP Toolkit
- * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ * Copyright (C) 2001 Red Hat, Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
 #include <stdio.h>
 #include "gtkvscale.h"
 #include "gtksignal.h"
-#include "gdk/gdkkeysyms.h"
 #include "gtkintl.h"
-#include "gtkbindings.h"
 
+#define VALUE_SPACING 2
 
-#define SCALE_CLASS(w)  GTK_SCALE_GET_CLASS (w)
-#define RANGE_CLASS(w)  GTK_RANGE_GET_CLASS (w)
-
-enum {
-  PROP_0
-};
+static gpointer parent_class;
 
 static void     gtk_vscale_class_init       (GtkVScaleClass *klass);
 static void     gtk_vscale_init             (GtkVScale      *vscale);
-static void     gtk_vscale_set_property     (GObject        *object,
-                                            guint           prop_id,
-                                            const GValue   *value,
-                                            GParamSpec     *pspec);
-static void     gtk_vscale_get_property     (GObject        *object,
-                                            guint           prop_id,
-                                            GValue         *value,
-                                            GParamSpec     *pspec);
-static void     gtk_vscale_realize          (GtkWidget      *widget);
-static void     gtk_vscale_size_request     (GtkWidget      *widget,
-                                            GtkRequisition *requisition);
-static void     gtk_vscale_size_allocate    (GtkWidget      *widget,
-                                            GtkAllocation  *allocation);
-static void     gtk_vscale_pos_trough       (GtkVScale      *vscale,
-                                            gint           *x,
-                                            gint           *y,
-                                            gint           *w,
-                                            gint           *h);
-static void     gtk_vscale_pos_background   (GtkVScale      *vscale,
-                                            gint           *x,
-                                            gint           *y,
-                                            gint           *w,
-                                            gint           *h);
-static void     gtk_vscale_draw_slider      (GtkRange       *range);
-static void     gtk_vscale_draw_value       (GtkScale       *scale);
-static void     gtk_vscale_clear_background (GtkRange       *range);
+static gboolean gtk_vscale_expose           (GtkWidget      *widget,
+                                             GdkEventExpose *event);
 
 GtkType
 gtk_vscale_get_type (void)
@@ -93,136 +63,32 @@ gtk_vscale_get_type (void)
   return vscale_type;
 }
 
-#define add_slider_binding(binding_set, keyval, mask, scroll, trough) \
-  gtk_binding_entry_add_signal (binding_set, keyval, mask,             \
-                                "move_slider", 2,                      \
-                                GTK_TYPE_SCROLL_TYPE, scroll,          \
-                                GTK_TYPE_TROUGH_TYPE, trough)
-
 static void
 gtk_vscale_class_init (GtkVScaleClass *class)
 {
-  GtkObjectClass *object_class;
   GObjectClass   *gobject_class;
   GtkWidgetClass *widget_class;
   GtkRangeClass *range_class;
-  GtkScaleClass *scale_class;
-  GtkBindingSet *binding_set;
   
-  object_class = (GtkObjectClass*) class;
   gobject_class = G_OBJECT_CLASS (class);
-  widget_class = (GtkWidgetClass*) class;
-  range_class = (GtkRangeClass*) class;
-  scale_class = (GtkScaleClass*) class;
-  
-  gobject_class->set_property = gtk_vscale_set_property;
-  gobject_class->get_property = gtk_vscale_get_property;
-  
-  widget_class->realize = gtk_vscale_realize;
-  widget_class->size_request = gtk_vscale_size_request;
-  widget_class->size_allocate = gtk_vscale_size_allocate;
-  
-  range_class->slider_update = _gtk_range_default_vslider_update;
-  range_class->trough_click = _gtk_range_default_vtrough_click;
-  range_class->motion = _gtk_range_default_vmotion;
-  range_class->draw_slider = gtk_vscale_draw_slider;
-  range_class->clear_background = gtk_vscale_clear_background;
-  
-  scale_class->draw_value = gtk_vscale_draw_value;
-
-  binding_set = gtk_binding_set_by_class (object_class);
-
-  add_slider_binding (binding_set, GDK_Up, 0,
-                      GTK_SCROLL_STEP_UP, GTK_TROUGH_NONE);
-
-  add_slider_binding (binding_set, GDK_Up, GDK_CONTROL_MASK,
-                      GTK_SCROLL_PAGE_UP, GTK_TROUGH_NONE);
-
-  add_slider_binding (binding_set, GDK_KP_Up, 0,
-                      GTK_SCROLL_STEP_UP, GTK_TROUGH_NONE);
-
-  add_slider_binding (binding_set, GDK_KP_Up, GDK_CONTROL_MASK,
-                      GTK_SCROLL_PAGE_UP, GTK_TROUGH_NONE);
-
-
-  add_slider_binding (binding_set, GDK_Down, 0,
-                      GTK_SCROLL_STEP_DOWN, GTK_TROUGH_NONE);
-
-  add_slider_binding (binding_set, GDK_Down, GDK_CONTROL_MASK,
-                      GTK_SCROLL_PAGE_DOWN, GTK_TROUGH_NONE);
-
-  add_slider_binding (binding_set, GDK_KP_Down, 0,
-                      GTK_SCROLL_STEP_DOWN, GTK_TROUGH_NONE);
-
-  add_slider_binding (binding_set, GDK_KP_Down, GDK_CONTROL_MASK,
-                      GTK_SCROLL_PAGE_DOWN, GTK_TROUGH_NONE);
-
-  add_slider_binding (binding_set, GDK_Page_Up, 0,
-                      GTK_SCROLL_PAGE_BACKWARD, GTK_TROUGH_NONE);
-
-  add_slider_binding (binding_set, GDK_KP_Page_Up, 0,
-                      GTK_SCROLL_PAGE_BACKWARD, GTK_TROUGH_NONE);  
-
-  add_slider_binding (binding_set, GDK_Page_Down, 0,
-                      GTK_SCROLL_PAGE_FORWARD, GTK_TROUGH_NONE);
-
-  add_slider_binding (binding_set, GDK_KP_Page_Down, 0,
-                      GTK_SCROLL_PAGE_FORWARD, GTK_TROUGH_NONE);
-
-  add_slider_binding (binding_set, GDK_Home, 0,
-                      GTK_SCROLL_NONE, GTK_TROUGH_START);
+  widget_class = GTK_WIDGET_CLASS (class);
+  range_class = GTK_RANGE_CLASS (class); 
 
-  add_slider_binding (binding_set, GDK_KP_Home, 0,
-                      GTK_SCROLL_NONE, GTK_TROUGH_START);
+  parent_class = g_type_class_peek_parent (class);
 
-
-  add_slider_binding (binding_set, GDK_End, 0,
-                      GTK_SCROLL_NONE, GTK_TROUGH_END);
-
-  add_slider_binding (binding_set, GDK_KP_End, 0,
-                      GTK_SCROLL_NONE, GTK_TROUGH_END);
-}
-
-static void
-gtk_vscale_set_property (GObject         *object,
-                        guint            prop_id,
-                        const GValue    *value,
-                        GParamSpec      *pspec)
-{
-  GtkVScale *vscale;
-  
-  vscale = GTK_VSCALE (object);
-  
-  switch (prop_id)
-    {
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-    }
-}
-
-static void
-gtk_vscale_get_property (GObject         *object,
-                        guint            prop_id,
-                        GValue          *value,
-                        GParamSpec      *pspec)
-{
-  GtkVScale *vscale;
-  
-  vscale = GTK_VSCALE (object);
+  range_class->slider_detail = "vscale";
   
-  switch (prop_id)
-    {
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-    }
+  widget_class->expose_event = gtk_vscale_expose;
 }
 
 static void
 gtk_vscale_init (GtkVScale *vscale)
 {
-  GTK_WIDGET_SET_FLAGS (vscale, GTK_NO_WINDOW);
+  GtkRange *range;
+
+  range = GTK_RANGE (vscale);
+  
+  range->orientation = GTK_ORIENTATION_VERTICAL;
 }
 
 GtkWidget*
@@ -237,298 +103,28 @@ gtk_vscale_new (GtkAdjustment *adjustment)
   return vscale;
 }
 
-
-static void
-gtk_vscale_realize (GtkWidget *widget)
-{
-  GtkRange *range;
-  GdkWindowAttr attributes;
-  gint attributes_mask;
-  gint x, y, w, h;
-  gint slider_width, slider_length;
-  
-  g_return_if_fail (widget != NULL);
-  g_return_if_fail (GTK_IS_VSCALE (widget));
-  
-  GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
-  range = GTK_RANGE (widget);
-
-  _gtk_range_get_props (range, &slider_width, NULL, NULL, NULL);
-  gtk_widget_style_get (widget, "slider_length", &slider_length, NULL);
-  
-  widget->window = gtk_widget_get_parent_window (widget);
-  gdk_window_ref (widget->window);
-  
-  gtk_vscale_pos_trough (GTK_VSCALE (widget), &x, &y, &w, &h);
-  
-  attributes.x = x;
-  attributes.y = y;
-  attributes.width = w;
-  attributes.height = h;
-  attributes.wclass = GDK_INPUT_OUTPUT;
-  attributes.window_type = GDK_WINDOW_CHILD;
-         
-  attributes.event_mask = gtk_widget_get_events (widget) | 
-    (GDK_EXPOSURE_MASK |
-     GDK_BUTTON_PRESS_MASK |
-     GDK_BUTTON_RELEASE_MASK |
-     GDK_ENTER_NOTIFY_MASK |
-     GDK_LEAVE_NOTIFY_MASK);
-  attributes.visual = gtk_widget_get_visual (widget);
-  attributes.colormap = gtk_widget_get_colormap (widget);
-  
-  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
-  
-  range->trough = gdk_window_new (widget->window, &attributes, attributes_mask);
-  
-  attributes.width = slider_width;
-  attributes.height = slider_length;
-  attributes.event_mask |= (GDK_BUTTON_MOTION_MASK |
-                            GDK_POINTER_MOTION_HINT_MASK);
-  
-  range->slider = gdk_window_new (range->trough, &attributes, attributes_mask);
-  
-  widget->style = gtk_style_attach (widget->style, widget->window);
-  
-  gdk_window_set_user_data (range->trough, widget);
-  gdk_window_set_user_data (range->slider, widget);
-  
-  gtk_style_set_background (widget->style, range->trough, GTK_STATE_ACTIVE);
-  gtk_style_set_background (widget->style, range->slider, GTK_STATE_NORMAL);
-  
-  _gtk_range_slider_update (GTK_RANGE (widget));
-  
-  gdk_window_show (range->slider);
-}
-
-static void
-gtk_vscale_clear_background (GtkRange    *range)
-{
-  GtkWidget *widget;
-  GtkScale *scale;
-  gint x, y, width, height;
-  
-  g_return_if_fail (range != NULL);
-  g_return_if_fail (GTK_IS_SCALE (range));
-  
-  widget = GTK_WIDGET (range);
-  scale = GTK_SCALE (range);
-  
-  gtk_vscale_pos_background (GTK_VSCALE (widget), &x, &y, &width, &height);
-  
-  gtk_widget_queue_clear_area (GTK_WIDGET (range),
-                               x, y, width, height);
-}
-
-static void
-gtk_vscale_size_request (GtkWidget      *widget,
-                         GtkRequisition *requisition)
-{
-  GtkScale *scale = GTK_SCALE (widget);
-  gint slider_width, slider_length, trough_border;
-  
-  _gtk_range_get_props (GTK_RANGE (scale),
-                       &slider_width, &trough_border, NULL, NULL);
-  gtk_widget_style_get (widget, "slider_length", &slider_length, NULL);
-    
-  requisition->width = (slider_width + trough_border * 2);
-  requisition->height = (slider_length + trough_border) * 2;
-  
-  if (scale->draw_value)
-    {
-      gint value_width, value_height;
-      gtk_scale_get_value_size (scale, &value_width, &value_height);
-      
-      if ((scale->value_pos == GTK_POS_LEFT) ||
-          (scale->value_pos == GTK_POS_RIGHT))
-        {
-          requisition->width += value_width + SCALE_CLASS (scale)->value_spacing;
-          if (requisition->height < (value_height))
-            requisition->height = value_height;
-        }
-      else if ((scale->value_pos == GTK_POS_TOP) ||
-               (scale->value_pos == GTK_POS_BOTTOM))
-        {
-          if (requisition->width < value_width)
-            requisition->width = value_width;
-          requisition->height += value_height;
-        }
-    }
-}
-
-static void
-gtk_vscale_size_allocate (GtkWidget     *widget,
-                          GtkAllocation *allocation)
+static gboolean
+gtk_vscale_expose (GtkWidget      *widget,
+                   GdkEventExpose *event)
 {
   GtkRange *range;
+  GtkVScale *vscale;
   GtkScale *scale;
-  gint width, height;
-  gint x, y;
-  
-  g_return_if_fail (widget != NULL);
-  g_return_if_fail (GTK_IS_VSCALE (widget));
-  g_return_if_fail (allocation != NULL);
-  
-  widget->allocation = *allocation;
-  if (GTK_WIDGET_REALIZED (widget))
-    {
-      range = GTK_RANGE (widget);
-      scale = GTK_SCALE (widget);
-      
-      gtk_vscale_pos_trough (GTK_VSCALE (widget), &x, &y, &width, &height);
-      
-      gdk_window_move_resize (range->trough, x, y, width, height);
-      _gtk_range_slider_update (GTK_RANGE (widget));
-    }
-}
-
-static void
-gtk_vscale_pos_trough (GtkVScale *vscale,
-                       gint      *x,
-                       gint      *y,
-                       gint      *w,
-                       gint      *h)
-{
-  GtkWidget *widget = GTK_WIDGET (vscale);
-  GtkScale *scale = GTK_SCALE (vscale);
-  gint value_width, value_height;
-  gint slider_width, trough_border;
-  
-  _gtk_range_get_props (GTK_RANGE (scale),
-                       &slider_width, &trough_border, NULL, NULL);
-    
-  *w = (slider_width + trough_border * 2);
-  *h = widget->allocation.height;
-  
-  if (scale->draw_value)
-    {
-      *x = 0;
-      *y = 0;
-      
-      gtk_scale_get_value_size (scale, &value_width, &value_height);
-
-      switch (scale->value_pos)
-        {
-        case GTK_POS_LEFT:
-          *x = (value_width + SCALE_CLASS (scale)->value_spacing +
-                (widget->allocation.width - widget->requisition.width) / 2);
-          break;
-        case GTK_POS_RIGHT:
-          *x = (widget->allocation.width - widget->requisition.width) / 2;
-          break;
-        case GTK_POS_TOP:
-          *x = (widget->allocation.width - *w) / 2;
-          *y = value_height;
-          *h -= *y;
-          break;
-        case GTK_POS_BOTTOM:
-          *x = (widget->allocation.width - *w) / 2;
-          *h -= value_height;
-          break;
-        }
-    }
-  else
-    {
-      *x = (widget->allocation.width - *w) / 2;
-      *y = 0;
-    }
-  *y += 1;
-  *h -= 2;
-  
-  *x += widget->allocation.x;
-  *y += widget->allocation.y;
-}
-
-static void
-gtk_vscale_pos_background (GtkVScale *vscale,
-                           gint      *x,
-                           gint      *y,
-                           gint      *w,
-                           gint      *h)
-{
-  GtkWidget *widget;
-  GtkScale *scale;
-  gint slider_width, trough_border;
-  
-  gint tx, ty, twidth, theight;
-  
-  g_return_if_fail (vscale != NULL);
-  g_return_if_fail (GTK_IS_VSCALE (vscale));
-  g_return_if_fail ((x != NULL) && (y != NULL) && (w != NULL) && (h != NULL));
-  
-  gtk_vscale_pos_trough (vscale, &tx, &ty, &twidth, &theight);
-  
-  widget = GTK_WIDGET (vscale);
-  scale = GTK_SCALE (vscale);
-  
-  *x = widget->allocation.x;
-  *y = widget->allocation.y;
-  *w = widget->allocation.width;
-  *h = widget->allocation.height;
-  
-  switch (scale->value_pos)
-    {
-    case GTK_POS_LEFT:
-      *w -= twidth;
-      break;
-    case GTK_POS_RIGHT:
-      *x += twidth;
-      *w -= twidth;
-      break;
-    case GTK_POS_TOP:
-      *h -= theight;
-      break;
-    case GTK_POS_BOTTOM:
-      *y += theight;
-      *h -= theight;
-      break;
-    }
-  *w = MAX (*w, 0);
-  *h = MAX (*h, 0);
-}
-
-static void
-gtk_vscale_draw_slider (GtkRange *range)
-{
-  GtkStateType state_type;
-  
-  g_return_if_fail (range != NULL);
-  g_return_if_fail (GTK_IS_VSCALE (range));
-  
-  if (range->slider)
-    {
-      if ((range->in_child == RANGE_CLASS (range)->slider) ||
-          (range->click_child == RANGE_CLASS (range)->slider))
-        state_type = GTK_STATE_PRELIGHT;
-      else
-        state_type = GTK_STATE_NORMAL;
-      
-      gtk_paint_slider (GTK_WIDGET (range)->style, range->slider, state_type, 
-                       GTK_SHADOW_OUT, 
-                       NULL, GTK_WIDGET (range), "vscale",
-                       0, 0, -1, -1, 
-                       GTK_ORIENTATION_VERTICAL); 
-    }
-}
-
-static void
-gtk_vscale_draw_value (GtkScale *scale)
-{
-  GtkStateType state_type;
-  GtkWidget *widget;
-  gint width, height;
-  gint x, y;
   
-  g_return_if_fail (scale != NULL);
-  g_return_if_fail (GTK_IS_VSCALE (scale));
-  
-  widget = GTK_WIDGET (scale);
+  range = GTK_RANGE (widget);
+  scale = GTK_SCALE (widget);
+  vscale = GTK_VSCALE (widget);
   
   if (scale->draw_value)
     {
       PangoLayout *layout;
       PangoRectangle logical_rect;
       gchar *txt;
+      gint x, y;
+      GtkStateType state_type;
+      gint value_spacing;
+
+      gtk_widget_style_get (widget, "value_spacing", &value_spacing, NULL);
       
       txt = _gtk_scale_format_value (scale,
                                      GTK_RANGE (scale)->adjustment->value);
@@ -537,44 +133,35 @@ gtk_vscale_draw_value (GtkScale *scale)
       g_free (txt);
       
       pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
-
+      
       switch (scale->value_pos)
         {
         case GTK_POS_LEFT:
-          gdk_window_get_position (GTK_RANGE (scale)->trough, &x, NULL);
-          gdk_window_get_position (GTK_RANGE (scale)->slider, NULL, &y);
-          gdk_window_get_size (GTK_RANGE (scale)->trough, &width, NULL);
-          gdk_window_get_size (GTK_RANGE (scale)->slider, NULL, &height);
-          
-          x -= SCALE_CLASS (scale)->value_spacing + logical_rect.width;
-          y += widget->allocation.y + (height - logical_rect.height) / 2 +
-                                       PANGO_ASCENT (logical_rect);
+          x = range->range_rect.x - logical_rect.width - value_spacing;
+          y = range->slider_start + (range->slider_end - range->slider_start - logical_rect.height) / 2;
+          y = CLAMP (y, 0, widget->allocation.height - logical_rect.height);
           break;
-        case GTK_POS_RIGHT:
-          gdk_window_get_position (GTK_RANGE (scale)->trough, &x, NULL);
-          gdk_window_get_position (GTK_RANGE (scale)->slider, NULL, &y);
-          gdk_window_get_size (GTK_RANGE (scale)->trough, &width, NULL);
-          gdk_window_get_size (GTK_RANGE (scale)->slider, NULL, &height);
           
-          x += width + SCALE_CLASS (scale)->value_spacing;
-          y += widget->allocation.y + (height - logical_rect.height) / 2 +
-                                       PANGO_ASCENT (logical_rect);
+        case GTK_POS_RIGHT:
+          x = range->range_rect.x + range->range_rect.width + value_spacing;
+          y = range->slider_start + (range->slider_end - range->slider_start - logical_rect.height) / 2;
+          y = CLAMP (y, 0, widget->allocation.height - logical_rect.height);
           break;
-        case GTK_POS_TOP:
-          gdk_window_get_position (GTK_RANGE (scale)->trough, &x, &y);
-          gdk_window_get_size (GTK_RANGE (scale)->slider, &width, NULL);
-          gdk_window_get_size (GTK_RANGE (scale)->trough, NULL, &height);
           
-          x += (width - logical_rect.width) / 2;
-          y -= PANGO_DESCENT (logical_rect);
+        case GTK_POS_TOP:
+          x = range->range_rect.x + (range->range_rect.width - logical_rect.width) / 2;
+          y = range->range_rect.y - logical_rect.height - value_spacing;
           break;
-        case GTK_POS_BOTTOM:
-          gdk_window_get_position (GTK_RANGE (scale)->trough, &x, &y);
-          gdk_window_get_size (GTK_RANGE (scale)->slider, &width, NULL);
-          gdk_window_get_size (GTK_RANGE (scale)->trough, NULL, &height);
           
-          x += (width - logical_rect.width) / 2;
-          y += height + PANGO_ASCENT (logical_rect);
+        case GTK_POS_BOTTOM:
+          x = range->range_rect.x + (range->range_rect.width - logical_rect.width) / 2;
+          y = range->range_rect.y + range->range_rect.height + value_spacing;
+          break;
+
+        default:
+          g_return_val_if_reached (FALSE);
+          x = 0;
+          y = 0;
           break;
         }
       
@@ -590,8 +177,10 @@ gtk_vscale_draw_value (GtkScale *scale)
                         widget,
                         "vscale",
                         x, y,
-                        layout);      
+                        layout);
 
       g_object_unref (G_OBJECT (layout));
     }
+  
+  return (* GTK_WIDGET_CLASS (parent_class)->expose_event) (widget, event);
 }
index 54fb337324e8b5e452cd865a663272c38758f840..795255b5eb7e4c417f1d4b8edc0a23017397aa20 100644 (file)
@@ -1,5 +1,6 @@
 /* GTK - The GIMP Toolkit
  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ * Copyright (C) 2001 Red Hat, Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
 #include "gdk/gdkkeysyms.h"
 #include "gtkintl.h"
 
-
-#define EPSILON 0.01
-
-#define RANGE_CLASS(w)  GTK_RANGE_GET_CLASS (w)
-
-enum {
-  PROP_0,
-};
-
 static void     gtk_vscrollbar_class_init       (GtkVScrollbarClass *klass);
 static void     gtk_vscrollbar_init             (GtkVScrollbar      *vscrollbar);
-static void     gtk_vscrollbar_set_property    (GObject            *object,
-                                                guint               prop_id,
-                                                const GValue       *value,
-                                                GParamSpec         *pspec);
-static void     gtk_vscrollbar_get_property     (GObject            *object,
-                                                guint               prop_id,
-                                                GValue             *value,
-                                                GParamSpec         *pspec);
-static void     gtk_vscrollbar_realize          (GtkWidget          *widget);
-static void     gtk_vscrollbar_size_request     (GtkWidget          *widget,
-                                                GtkRequisition     *requisition);
-static void     gtk_vscrollbar_size_allocate    (GtkWidget          *widget,
-                                                GtkAllocation      *allocation);
-static void     gtk_vscrollbar_draw_step_forw   (GtkRange           *range);
-static void     gtk_vscrollbar_draw_step_back   (GtkRange           *range);
-static void     gtk_vscrollbar_slider_update    (GtkRange           *range);
-static void     gtk_vscrollbar_calc_slider_size (GtkVScrollbar      *vscrollbar);
 
 GtkType
 gtk_vscrollbar_get_type (void)
@@ -86,67 +61,17 @@ gtk_vscrollbar_get_type (void)
 static void
 gtk_vscrollbar_class_init (GtkVScrollbarClass *class)
 {
-  GObjectClass   *gobject_class;
-  GtkWidgetClass *widget_class;
-  GtkRangeClass *range_class;
-  
-  gobject_class = G_OBJECT_CLASS (class);
-  widget_class = (GtkWidgetClass*) class;
-  range_class = (GtkRangeClass*) class;
-  
-  gobject_class->set_property = gtk_vscrollbar_set_property;
-  gobject_class->get_property = gtk_vscrollbar_get_property;
-  
-  widget_class->realize = gtk_vscrollbar_realize;
-  widget_class->size_request = gtk_vscrollbar_size_request;
-  widget_class->size_allocate = gtk_vscrollbar_size_allocate;
-  
-  range_class->draw_step_forw = gtk_vscrollbar_draw_step_forw;
-  range_class->draw_step_back = gtk_vscrollbar_draw_step_back;
-  range_class->slider_update = gtk_vscrollbar_slider_update;
-  range_class->trough_click = _gtk_range_default_vtrough_click;
-  range_class->motion = _gtk_range_default_vmotion;
+  GTK_RANGE_CLASS (class)->stepper_detail = "vscrollbar";
 }
 
 static void
-gtk_vscrollbar_set_property (GObject         *object,
-                            guint            prop_id,
-                            const GValue    *value,
-                            GParamSpec      *pspec)
+gtk_vscrollbar_init (GtkVScrollbar *vscrollbar)
 {
-  GtkVScrollbar *vscrollbar;
-  
-  vscrollbar = GTK_VSCROLLBAR (object);
-  
-  switch (prop_id)
-    {
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-    }
-}
+  GtkRange *range;
 
-static void
-gtk_vscrollbar_get_property (GObject         *object,
-                            guint            prop_id,
-                            GValue          *value,
-                            GParamSpec      *pspec)
-{
-  GtkVScrollbar *vscrollbar;
-  
-  vscrollbar = GTK_VSCROLLBAR (object);
-  
-  switch (prop_id)
-    {
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-    }
-}
+  range = GTK_RANGE (vscrollbar);
 
-static void
-gtk_vscrollbar_init (GtkVScrollbar *vscrollbar)
-{
+  range->orientation = GTK_ORIENTATION_VERTICAL;
 }
 
 GtkWidget*
@@ -160,282 +85,3 @@ gtk_vscrollbar_new (GtkAdjustment *adjustment)
   
   return vscrollbar;
 }
-
-
-static void
-gtk_vscrollbar_realize (GtkWidget *widget)
-{
-  GtkRange *range;
-  GdkWindowAttr attributes;
-  gint attributes_mask;
-  gint slider_width;
-  gint stepper_size;
-  gint trough_border;
-  
-  g_return_if_fail (widget != NULL);
-  g_return_if_fail (GTK_IS_VSCROLLBAR (widget));
-  
-  GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
-  range = GTK_RANGE (widget);
-  
-  _gtk_range_get_props (range, &slider_width, &trough_border,
-                       &stepper_size, NULL);
-
-  attributes.x = widget->allocation.x + (widget->allocation.width - widget->requisition.width) / 2;
-  attributes.y = widget->allocation.y;
-  attributes.width = widget->requisition.width;
-  attributes.height = widget->allocation.height;
-  attributes.wclass = GDK_INPUT_OUTPUT;
-  attributes.window_type = GDK_WINDOW_CHILD;
-  attributes.visual = gtk_widget_get_visual (widget);
-  attributes.colormap = gtk_widget_get_colormap (widget);
-  attributes.event_mask = gtk_widget_get_events (widget);
-  attributes.event_mask |= (GDK_EXPOSURE_MASK |
-                            GDK_BUTTON_PRESS_MASK |
-                            GDK_BUTTON_RELEASE_MASK |
-                            GDK_ENTER_NOTIFY_MASK |
-                            GDK_LEAVE_NOTIFY_MASK);
-  
-  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
-  widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
-  
-  range->trough = widget->window;
-  gdk_window_ref (range->trough);
-  
-  attributes.x = trough_border;
-  attributes.y = trough_border;
-  attributes.width = stepper_size;
-  attributes.height = stepper_size;
-  
-  range->step_back = gdk_window_new (range->trough, &attributes, attributes_mask);
-  
-  attributes.y = (widget->allocation.height -
-                  trough_border -
-                  stepper_size);
-  
-  range->step_forw = gdk_window_new (range->trough, &attributes, attributes_mask);
-  
-  attributes.x = trough_border;
-  attributes.y = 0;
-  attributes.width = slider_width;
-  attributes.height = RANGE_CLASS (widget)->min_slider_size;
-  attributes.event_mask |= (GDK_BUTTON_MOTION_MASK |
-                            GDK_POINTER_MOTION_HINT_MASK);
-  
-  range->slider = gdk_window_new (range->trough, &attributes, attributes_mask);
-  
-  gtk_vscrollbar_calc_slider_size (GTK_VSCROLLBAR (widget));
-  _gtk_range_slider_update (GTK_RANGE (widget));
-  
-  widget->style = gtk_style_attach (widget->style, widget->window);
-  
-  gdk_window_set_user_data (range->trough, widget);
-  gdk_window_set_user_data (range->slider, widget);
-  gdk_window_set_user_data (range->step_forw, widget);
-  gdk_window_set_user_data (range->step_back, widget);
-  
-  gtk_style_set_background (widget->style, range->trough, GTK_STATE_ACTIVE);
-  gtk_style_set_background (widget->style, range->slider, GTK_STATE_NORMAL);
-  gtk_style_set_background (widget->style, range->step_forw, GTK_STATE_ACTIVE);
-  gtk_style_set_background (widget->style, range->step_back, GTK_STATE_ACTIVE);
-  
-  gdk_window_show (range->slider);
-  gdk_window_show (range->step_forw);
-  gdk_window_show (range->step_back);
-}
-
-static void
-gtk_vscrollbar_size_request (GtkWidget      *widget,
-                            GtkRequisition *requisition)
-{
-  gint slider_width;
-  gint trough_border;
-  gint stepper_size;
-  gint stepper_spacing;
-  
-  GtkRange *range = GTK_RANGE (widget);
-
-  _gtk_range_get_props (range, &slider_width, &trough_border,
-                       &stepper_size, &stepper_spacing);
-  
-  requisition->width = (slider_width +
-                        trough_border * 2);
-  requisition->height = (RANGE_CLASS (widget)->min_slider_size +
-                         stepper_size +
-                         stepper_spacing +
-                         trough_border) * 2;
-}
-
-static void
-gtk_vscrollbar_size_allocate (GtkWidget     *widget,
-                              GtkAllocation *allocation)
-{
-  GtkRange *range;
-  gint trough_border;
-  gint stepper_size;
-  
-  g_return_if_fail (widget != NULL);
-  g_return_if_fail (GTK_IS_VSCROLLBAR (widget));
-  g_return_if_fail (allocation != NULL);
-  
-  widget->allocation = *allocation;
-  if (GTK_WIDGET_REALIZED (widget))
-    {
-      range = GTK_RANGE (widget);
-      
-      _gtk_range_get_props (range, NULL, &trough_border, 
-                           &stepper_size, NULL);
-  
-      gdk_window_move_resize (range->trough,
-                              allocation->x + (allocation->width - widget->requisition.width) / 2,
-                              allocation->y,
-                              widget->requisition.width, allocation->height);
-      gdk_window_move_resize (range->step_back,
-                              trough_border,
-                              trough_border,
-                              widget->requisition.width - trough_border * 2,
-                              stepper_size);
-      gdk_window_move_resize (range->step_forw,
-                              trough_border,
-                              allocation->height - trough_border -
-                              stepper_size,
-                              widget->requisition.width - trough_border * 2,
-                              stepper_size);
-      
-      _gtk_range_slider_update (GTK_RANGE (widget));
-    }
-}
-
-static void
-gtk_vscrollbar_draw_step_forw (GtkRange *range)
-{
-  GtkStateType state_type;
-  GtkShadowType shadow_type;
-  
-  g_return_if_fail (range != NULL);
-  g_return_if_fail (GTK_IS_VSCROLLBAR (range));
-  
-  if (GTK_WIDGET_DRAWABLE (range))
-    {
-      if (range->in_child == RANGE_CLASS (range)->step_forw)
-        {
-          if (range->click_child == RANGE_CLASS (range)->step_forw)
-            state_type = GTK_STATE_ACTIVE;
-          else
-            state_type = GTK_STATE_PRELIGHT;
-        }
-      else
-        state_type = GTK_STATE_NORMAL;
-      
-      if (range->click_child == RANGE_CLASS (range)->step_forw)
-        shadow_type = GTK_SHADOW_IN;
-      else
-        shadow_type = GTK_SHADOW_OUT;
-      
-      gtk_paint_arrow (GTK_WIDGET (range)->style, range->step_forw,
-                       state_type, shadow_type, 
-                       NULL, GTK_WIDGET (range), "vscrollbar",
-                       GTK_ARROW_DOWN,
-                       TRUE, 0, 0, -1, -1);
-    }
-}
-
-static void
-gtk_vscrollbar_draw_step_back (GtkRange *range)
-{
-  GtkStateType state_type;
-  GtkShadowType shadow_type;
-  
-  g_return_if_fail (range != NULL);
-  g_return_if_fail (GTK_IS_VSCROLLBAR (range));
-  
-  if (GTK_WIDGET_DRAWABLE (range))
-    {
-      if (range->in_child == RANGE_CLASS (range)->step_back)
-        {
-          if (range->click_child == RANGE_CLASS (range)->step_back)
-            state_type = GTK_STATE_ACTIVE;
-          else
-            state_type = GTK_STATE_PRELIGHT;
-        }
-      else
-        state_type = GTK_STATE_NORMAL;
-      
-      if (range->click_child == RANGE_CLASS (range)->step_back)
-        shadow_type = GTK_SHADOW_IN;
-      else
-        shadow_type = GTK_SHADOW_OUT;
-      
-      gtk_paint_arrow (GTK_WIDGET (range)->style, range->step_back,
-                       state_type, shadow_type, 
-                       NULL, GTK_WIDGET (range), "vscrollbar",
-                       GTK_ARROW_UP,
-                       TRUE, 0, 0, -1, -1);
-    }
-}
-
-static void
-gtk_vscrollbar_slider_update (GtkRange *range)
-{
-  g_return_if_fail (range != NULL);
-  g_return_if_fail (GTK_IS_VSCROLLBAR (range));
-  
-  gtk_vscrollbar_calc_slider_size (GTK_VSCROLLBAR (range));
-  _gtk_range_default_vslider_update (range);
-}
-
-static void
-gtk_vscrollbar_calc_slider_size (GtkVScrollbar *vscrollbar)
-{
-  GtkRange *range;
-  gint step_back_y;
-  gint step_back_height;
-  gint step_forw_y;
-  gint stepper_spacing;
-  gint slider_width;
-  gint slider_height;
-  gint top, bottom;
-  gint height;
-  
-  g_return_if_fail (vscrollbar != NULL);
-  g_return_if_fail (GTK_IS_VSCROLLBAR (vscrollbar));
-  
-  if (GTK_WIDGET_REALIZED (vscrollbar))
-    {
-      range = GTK_RANGE (vscrollbar);
-      
-      _gtk_range_get_props (range, NULL, NULL, NULL, &stepper_spacing);
-      
-      gdk_window_get_size (range->step_back, NULL, &step_back_height);
-      gdk_window_get_position (range->step_back, NULL, &step_back_y);
-      gdk_window_get_position (range->step_forw, NULL, &step_forw_y);
-      
-      top = (step_back_y +
-             step_back_height +
-             stepper_spacing);
-      bottom = step_forw_y - stepper_spacing;
-      height = bottom - top;
-      
-      if ((range->adjustment->page_size > 0) &&
-          (range->adjustment->lower != range->adjustment->upper))
-        {
-          if (range->adjustment->page_size >
-              (range->adjustment->upper - range->adjustment->lower))
-            range->adjustment->page_size = range->adjustment->upper - range->adjustment->lower;
-          
-          height = (height * range->adjustment->page_size /
-                    (range->adjustment->upper - range->adjustment->lower));
-          
-          if (height < RANGE_CLASS (vscrollbar)->min_slider_size)
-            height = RANGE_CLASS (vscrollbar)->min_slider_size;
-        }
-      
-      gdk_window_get_size (range->slider, &slider_width, &slider_height);
-      
-      if (slider_height != height)
-       {
-         gdk_window_resize (range->slider, slider_width, height);
-         gdk_window_invalidate_rect (range->slider, NULL, FALSE);
-       }
-    }
-}
index b6dc0861e4e4f9f8e89d4cecd163a5c36766e27c..c0f645a9da0989e232d1f7f072428c785c18ff45 100644 (file)
@@ -6680,7 +6680,8 @@ static gchar*
 reformat_value (GtkScale *scale,
                 gdouble   value)
 {
-  return g_strdup_printf ("-->%g<--", value);
+  return g_strdup_printf ("-->%0.*g<--",
+                          gtk_scale_get_digits (scale), value);
 }
 
 static void